summaryrefslogtreecommitdiff
path: root/node_modules/mmmagic/deps
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mmmagic/deps')
-rw-r--r--node_modules/mmmagic/deps/libmagic/AUTHORS1
-rw-r--r--node_modules/mmmagic/deps/libmagic/COPYING29
-rw-r--r--node_modules/mmmagic/deps/libmagic/ChangeLog1716
-rw-r--r--node_modules/mmmagic/deps/libmagic/INSTALL365
-rw-r--r--node_modules/mmmagic/deps/libmagic/MAINT44
-rw-r--r--node_modules/mmmagic/deps/libmagic/NEWS1
-rw-r--r--node_modules/mmmagic/deps/libmagic/README161
-rw-r--r--node_modules/mmmagic/deps/libmagic/TODO36
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/freebsd/config.h365
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/linux/config.h405
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/mac/config.h360
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/openbsd/config.h334
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/sunos/config.h370
-rw-r--r--node_modules/mmmagic/deps/libmagic/config/win/config.h367
-rw-r--r--node_modules/mmmagic/deps/libmagic/libmagic.gyp85
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/dirent.h372
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/inttypes.h305
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/COPYING.LIB510
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/Makefile41
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README33
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README.md10
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regcomp.c3800
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.c74
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.h556
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.c1717
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.h778
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regexec.c4329
-rw-r--r--node_modules/mmmagic/deps/libmagic/msvc/stdint.h247
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/BNF151
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/apprentice.c3429
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/apptype.c169
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/ascmagic.c361
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/asctime_r.c19
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/asprintf.c45
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/cdf.c1629
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/cdf.h352
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/cdf_time.c198
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/compress.c762
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/ctime_r.c19
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/der.c409
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/der.h28
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/dprintf.c61
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/elfclass.h82
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/encoding.c529
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/file.c640
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/file.h653
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/file_opts.h58
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/fmtcheck.c251
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/fsmagic.c418
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/funcs.c603
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/getline.c107
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/getopt_long.c498
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/gmtime_r.c19
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/is_tar.c159
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/localtime_r.c19
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/magic.c662
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/magic.h156
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/mygetopt.h68
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/pread.c26
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/print.c264
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/readcdf.c680
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/readelf.c1640
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/readelf.h433
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/snprintf.c26
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/softmagic.c2076
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/strcasestr.c84
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/strlcat.c58
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/strlcpy.c54
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/tar.h73
-rw-r--r--node_modules/mmmagic/deps/libmagic/src/vasprintf.c27
70 files changed, 35406 insertions, 0 deletions
diff --git a/node_modules/mmmagic/deps/libmagic/AUTHORS b/node_modules/mmmagic/deps/libmagic/AUTHORS
new file mode 100644
index 0000000..3d3d34a
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/AUTHORS
@@ -0,0 +1 @@
+See COPYING. \ No newline at end of file
diff --git a/node_modules/mmmagic/deps/libmagic/COPYING b/node_modules/mmmagic/deps/libmagic/COPYING
new file mode 100644
index 0000000..b3db8b2
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/COPYING
@@ -0,0 +1,29 @@
+$File: COPYING,v 1.1 2008/02/05 19:08:11 christos Exp $
+Copyright (c) Ian F. Darwin 1986, 1987, 1989, 1990, 1991, 1992, 1994, 1995.
+Software written by Ian F. Darwin and others;
+maintained 1994- Christos Zoulas.
+
+This software is not subject to any export provision of the United States
+Department of Commerce, and may be exported to any country or planet.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice immediately at the beginning of the file, without modification,
+ this list of conditions, and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/node_modules/mmmagic/deps/libmagic/ChangeLog b/node_modules/mmmagic/deps/libmagic/ChangeLog
new file mode 100644
index 0000000..2063a23
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/ChangeLog
@@ -0,0 +1,1716 @@
+2017-09-02 11:53 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.32
+
+2017-08-28 16:37 Christos Zoulas <christos@zoulas.com>
+
+ * Always reset state in {file,buffer}_apprentice (Krzysztof Wilczynski)
+
+2017-08-27 03:55 Christos Zoulas <christos@zoulas.com>
+
+ * Fix always true condition (Thomas Jarosch)
+
+2017-05-24 17:30 Christos Zoulas <christos@zoulas.com>
+
+ * pickier parsing of numeric values in magic files.
+
+2017-05-23 17:55 Christos Zoulas <christos@zoulas.com>
+
+ * PR/615 add magic_getflags()
+
+2017-05-23 13:55 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.31
+
+2017-03-17 20:32 Christos Zoulas <christos@zoulas.com>
+
+ * remove trailing spaces from magic files
+ * refactor is_tar
+ * better bounds checks for cdf
+
+2017-02-10 12:24 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.30
+
+2017-02-07 23:27 Christos Zoulas <christos@zoulas.com>
+
+ * If we exceeded the offset in a search return no match
+ (Christoph Biedl)
+ * Be more lenient on corrupt CDF files (Christoph Biedl)
+
+2017-02-04 16:46 Christos Zoulas <christos@zoulas.com>
+
+ * pacify ubsan sign extension (oss-fuzz/524)
+
+2017-02-01 12:42 Christos Zoulas <christos@zoulas.com>
+
+ * off by one in cdf parsing (PR/593)
+ * report debugging sections in elf (PR/591)
+
+2016-11-06 10:52 Christos Zoulas <christos@zoulas.com>
+
+ * Allow @@@ in extensions
+ * Add missing overflow check in der magic (Jonas Wagner)
+
+2016-10-25 10:40 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.29
+
+2016-10-24 11:20 Christos Zoulas <christos@zoulas.com>
+
+ * der getlength overflow (Jonas Wagner)
+ * multiple magic file load failure (Christoph Biedl)
+
+2016-10-17 11:26 Christos Zoulas <christos@zoulas.com>
+
+ * CDF parsing improvements (Guy Helmer)
+
+2016-07-20 7:26 Christos Zoulas <christos@zoulas.com>
+
+ * Add support for signed indirect offsets
+
+2016-07-18 7:41 Christos Zoulas <christos@zoulas.com>
+
+ * cat /dev/null | file - should print empty (Christoph Biedl)
+
+2016-07-05 15:20 Christos Zoulas <christos@zoulas.com>
+
+ * Bump string size from 64 to 96.
+
+2016-06-13 20:20 Christos Zoulas <christos@zoulas.com>
+
+ * PR/556: Fix separators on annotations.
+
+2016-06-13 19:40 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.28
+ * fix leak on allocation failure
+
+2016-06-01 1:20 Christos Zoulas <christos@zoulas.com>
+
+ * PR/555: Avoid overflow for offset > nbytes
+ * PR/550: Segv on DER parsing:
+ - use the correct variable for length
+ - set offset to 0 on failure.
+
+2016-05-13 12:00 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.27
+
+2016-04-18 9:35 Christos Zoulas <christos@zoulas.com>
+
+ * Errors comparing DER entries or computing offsets
+ are just indications of malformed non-DER files.
+ Don't print them.
+ * Offset comparison was off-by-one.
+ * Fix compression code (Werner Fink)
+ * Put new bytes constant in the right file (not the generated one)
+
+2016-04-16 18:34 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.26
+
+2016-03-31 13:50 Christos Zoulas <christos@zoulas.com>
+
+ * make the number of bytes read from files configurable.
+
+2016-03-21 13:40 Christos Zoulas <christos@zoulas.com>
+
+ * Add bounds checks for DER code (discovered by Thomas Jarosch)
+ * Change indirect recursion limit to indirect use count and
+ bump from 15 to 50 to prevent abuse.
+
+2016-03-13 20:39 Christos Zoulas <christos@zoulas.com>
+
+ * Add -00 which prints filename\0description\0
+
+2016-03-01 13:28 Christos Zoulas <christos@zoulas.com>
+
+ * Fix ID3 indirect parsing
+
+2016-01-19 10:18 Christos Zoulas <christos@zoulas.com>
+
+ * add DER parsing capability
+
+2015-11-13 10:35 Christos Zoulas <christos@zoulas.com>
+
+ * provide dprintf(3) for the OS's that don't have it.
+
+2015-11-11 16:25 Christos Zoulas <christos@zoulas.com>
+
+ * redo the compression code report decompression errors
+
+2015-11-10 23:25 Christos Zoulas <christos@zoulas.com>
+
+ * REG_STARTEND code is not working as expected, delete it.
+
+2015-11-09 16:05 Christos Zoulas <christos@zoulas.com>
+
+ * Add zlib support if we have it.
+
+2015-11-05 11:22 Christos Zoulas <christos@zoulas.com>
+
+ * PR/492: compression forking was broken with magic_buffer.
+
+2015-09-16 9:50 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.25
+
+2015-09-11 13:25 Christos Zoulas <christos@zoulas.com>
+
+ * add a limit to the length of regex searches
+
+2015-09-08 9:50 Christos Zoulas <christos@zoulas.com>
+
+ * fix problems with --parameter (Christoph Biedl)
+
+2015-07-11 10:35 Christos Zoulas <christos@zoulas.com>
+
+ * Windows fixes PR/466 (Jason Hood)
+
+2015-07-09 10:35 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.24
+
+2015-06-11 8:52 Christos Zoulas <christos@zoulas.com>
+
+ * redo long option encoding to fix off-by-one in 5.23
+
+2015-06-10 13:50 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.23
+
+2015-06-09 16:10 Christos Zoulas <christos@zoulas.com>
+
+ * Fix issue with regex range for magic with offset
+ * Always return true from mget with USE (success to mget not match
+ indication). Fixes mime evaluation after USE magic
+ * PR/459: Don't insert magic entries to the list if there are parsing
+ errors for them.
+
+2015-06-03 16:00 Christos Zoulas <christos@zoulas.com>
+
+ * PR/455: Add utf-7 encoding
+
+2015-06-03 14:30 Christos Zoulas <christos@zoulas.com>
+
+ * PR/455: Implement -Z, look inside, but don't report on compression
+ * PR/454: Fix allocation error on bad magic.
+
+2015-05-29 10:30 Christos Zoulas <christos@zoulas.com>
+
+ * handle MAGIC_CONTINUE everywhere, not just in softmagic
+
+2015-05-21 14:30 Christos Zoulas <christos@zoulas.com>
+
+ * don't print descriptions for NAME types when mime.
+
+2015-04-09 15:59 Christos Zoulas <christos@zoulas.com>
+
+ * Add --extension to list the known extensions for this file type
+ Idea by Andrew J Roazen
+
+2015-02-14 12:23 Christos Zoulas <christos@zoulas.com>
+
+ * Bump file search buffer size to 1M.
+
+2015-01-09 14:35 Christos Zoulas <christos@zoulas.com>
+
+ * Fix multiple issues with date formats reported by Christoph Biedl:
+ - T_LOCAL meaning was reversed
+ - Arithmetic did not work
+ Also stop adjusting daylight savings for gmt printing.
+
+2015-01-05 13:00 Christos Zoulas <christos@zoulas.com>
+
+ * PR/411: Fix memory corruption from corrupt cdf file.
+
+2015-01-02 15:15 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.22
+
+2015-01-01 12:01 Christos Zoulas <christos@zoulas.com>
+
+ * add indirect relative for TIFF/Exif
+
+2014-12-16 18:10 Christos Zoulas <christos@zoulas.com>
+
+ * restructure elf note printing to avoid repeated messages
+ * add note limit, suggested by Alexander Cherepanov
+
+2014-12-16 16:53 Christos Zoulas <christos@zoulas.com>
+
+ * Bail out on partial pread()'s (Alexander Cherepanov)
+ * Fix incorrect bounds check in file_printable (Alexander Cherepanov)
+
+2014-12-11 20:01 Christos Zoulas <christos@zoulas.com>
+
+ * PR/405: ignore SIGPIPE from uncompress programs
+ * change printable -> file_printable and use it in
+ more places for safety
+ * in ELF, instead of "(uses dynamic libraries)" when PT_INTERP
+ is present print the interpreter name.
+
+2014-12-10 20:01 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.21
+
+2014-11-27 18:40 Christos Zoulas <christos@zoulas.com>
+
+ * Allow setting more parameters from the command line.
+ * Split name/use and indirect magic recursion limits.
+
+2014-11-27 11:12 Christos Zoulas <christos@zoulas.com>
+
+ * Adjust ELF parameters and the default recursion
+ level.
+ * Allow setting the recursion level dynamically.
+
+2014-11-24 8:55 Christos Zoulas <christos@zoulas.com>
+
+ * The following fixes resulted from Thomas Jarosch's fuzzing
+ tests that revealed severe performance issues on pathological
+ input:
+ - limit number of elf program and sections processing
+ - abort elf note processing quickly
+ - reduce the number of recursion levels from 20 to 10
+ - preserve error messages in indirect magic handling
+
+ This is tracked as CVE-2014-8116 and CVE-2014-8117
+
+2014-11-12 10:30 Christos Zoulas <christos@zoulas.com>
+
+ * fix bogus free in the user buffer case.
+
+2014-11-11 12:35 Christos Zoulas <christos@zoulas.com>
+
+ * fix out of bounds read for pascal strings
+ * fix memory leak (not freeing the head of each mlist)
+
+2014-11-07 10:25 Christos Zoulas <christos@zoulas.com>
+
+ * When printing strings from a file, convert them to printable
+ on a byte by byte basis, so that we don't get issues with
+ locale's trying to interpret random byte streams as UTF-8 and
+ having printf error out with EILSEQ.
+
+2014-10-17 11:48 Christos Zoulas <christos@zoulas.com>
+
+ * fix bounds in note reading (Francisco Alonso / Red Hat)
+
+2014-10-11 15:02 Christos Zoulas <christos@zoulas.com>
+
+ * fix autoconf glue for setlocale and locale_t; some OS's
+ have locale_t in xlocale.h
+
+2014-10-10 15:01 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.20
+
+2014-08-17 10:01 Christos Zoulas <christos@zoulas.com>
+
+ * recognize encrypted CDF documents
+
+2014-08-04 9:18 Christos Zoulas <christos@zoulas.com>
+
+ * add magic_load_buffers from Brooks Davis
+
+2014-07-24 16:40 Christos Zoulas <christos@zoulas.com>
+
+ * add thumbs.db support
+
+2014-06-12 12:28 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.19
+
+2014-06-09 9:04 Christos Zoulas <christos@zoulas.com>
+
+ * Misc buffer overruns and missing buffer size tests in cdf parsing
+ (Francisco Alonso, Jan Kaluza)
+
+2014-06-02 14:50 Christos Zoulas <christos@zoulas.com>
+
+ * Enforce limit of 8K on regex searches that have no limits
+ * Allow the l modifier for regex to mean line count. Default
+ to byte count. If line count is specified, assume a max
+ of 80 characters per line to limit the byte count.
+ * Don't allow conversions to be used for dates, allowing
+ the mask field to be used as an offset.
+
+2014-05-30 12:51 Christos Zoulas <christos@zoulas.com>
+
+ * Make the range operator limit the length of the
+ regex search.
+
+2014-05-14 19:23 Christos Zoulas <christos@zoulas.com>
+
+ * PR/347: Windows fixes
+ * PR/352: Hangul word processor recognition
+ * PR/354: Encoding irregularities in text files
+
+2014-05-06 6:12 Christos Zoulas <christos@zoulas.com>
+
+ * Fix uninitialized title in CDF files (Jan Kaluza)
+
+2014-05-04 14:55 Christos Zoulas <christos@zoulas.com>
+
+ * PR/351: Fix compilation of empty files
+
+2014-04-30 17:39 Christos Zoulas <christos@zoulas.com>
+
+ * Fix integer formats: We don't specify 'l' or
+ 'h' and 'hh' specifiers anymore, only 'll' for
+ quads and nothing for the rest. This is so that
+ magic writing is simpler.
+
+2014-04-01 15:25 Christos Zoulas <christos@zoulas.com>
+
+ * PR/341: Jan Kaluza, fix memory leak
+ * PR/342: Jan Kaluza, fix out of bounds read
+
+2014-03-28 15:25 Christos Zoulas <christos@zoulas.com>
+
+ * Fix issue with long formats not matching fmtcheck
+
+2014-03-26 11:25 Christos Zoulas <christos@zoulas.com>
+
+ * release 5.18
+
+2014-03-15 17:45 Christos Zoulas <christos@zoulas.com>
+
+ * add fmtcheck(3) for those who don't have it
+
+2014-03-14 15:12 Christos Zoulas <christos@zoulas.com>
+
+ * prevent mime entries from being attached to magic
+ entries with no descriptions
+
+ * adjust magic strength for regex type
+
+ * remove superfluous ascmagic with encoding test
+
+2014-03-06 12:01 Christos Zoulas <christos@zoulas.com>
+
+ * fix regression fix echo -ne "\012\013\014" | file -i -
+ which printed "binary" instead of "application/octet-stream"
+
+ * add size_t overflow check for magic file size
+
+2014-02-27 16:01 Christos Zoulas <christos@zoulas.com>
+
+ * experimental support for matching with CFD CLSID
+
+2014-02-18 13:04 Kimmo Suominen (kimmo@suominen.com)
+
+ * Cache old LC_CTYPE locale before setting it to "C", so
+ we can use it to restore LC_CTYPE instead of asking
+ setlocale() to scan the environment variables.
+
+2014-02-12 18:21 Christos Zoulas <christos@zoulas.com>
+
+ * Count recursion levels through indirect magic
+
+2014-02-11 10:40 Christos Zoulas <christos@zoulas.com>
+
+ * Prevent infinite recursion on files with indirect offsets of 0
+
+2014-01-30 21:00 Christos Zoulas <christos@zoulas.com>
+
+ * Add -E flag that makes file print filesystem errors to stderr
+ and exit.
+
+2014-01-08 17:20 Christos Zoulas <christos@zoulas.com>
+
+ * mime printing could print results from multiple magic entries
+ if there were multiple matches.
+ * in some cases overflow was not detected when computing offsets
+ in softmagic.
+
+2013-12-05 12:00 Christos Zoulas <christos@zoulas.com>
+
+ * use strcasestr() to for cdf strings
+ * reset to the "C" locale while doing regex operations, or case
+ insensitive comparisons; this is provisional
+
+2013-11-19 20:10 Christos Zoulas <christos@zoulas.com>
+
+ * always leave magic file loaded, don't unload for magic_check, etc.
+ * fix default encoding to binary instead of unknown which broke recently
+ * handle empty and one byte files, less specially so that
+ --mime-encoding does not break completely.
+ `
+2013-11-06 14:40 Christos Zoulas <christos@zoulas.com>
+
+ * fix erroneous non-zero exit code from non-existent file and message
+
+2013-10-29 14:25 Christos Zoulas <christos@zoulas.com>
+
+ * add CDF MSI file detection (Guy Helmer)
+
+2013-09-03 11:56 Christos Zoulas <christos@zoulas.com>
+
+ * Don't mix errors and regular output if there was an error
+ * in magic_descriptor() don't close the file and try to restore
+ its position
+
+2013-05-30 17:25 Christos Zoulas <christos@zoulas.com>
+
+ * Don't treat magic as an error if offset was past EOF (Christoph Biedl)
+
+2013-05-28 17:25 Christos Zoulas <christos@zoulas.com>
+
+ * Fix spacing issues in softmagic and elf (Jan Kaluza)
+
+2013-05-02 18:00 Christos Zoulas <christos@zoulas.com>
+
+ * Fix segmentation fault with multiple magic_load commands.
+
+2013-04-22 11:20 Christos Zoulas <christos@zoulas.com>
+
+ * The way "default" was implemented was not very useful
+ because the "if something was printed at that level"
+ was not easily controlled by the user, and the format
+ was bound to a string which is too restrictive. Add
+ a "clear" for that level keyword and make "default"
+ void. This way one can do:
+
+ >>13 clear x
+ >>13 lelong 1 foo
+ >>13 lelong 2 bar
+ >>13 default x
+ >>>13 lelong x unknown %x
+
+2013-03-25 13:20 Christos Zoulas <christos@zoulas.com>
+
+ * disallow strength setting in "name" entries
+
+2013-03-06 21:24 Christos Zoulas <christos@zoulas.com>
+
+ * fix recursive magic separator printing
+
+2013-02-26 19:28 Christos Zoulas <christos@zoulas.com>
+
+ * limit recursion level for mget
+ * fix pread() related breakage in cdf
+ * handle offsets properly in recursive "use"
+
+2013-02-18 10:39 Christos Zoulas <christos@zoulas.com>
+
+ * add elf reading of debug info to determine if file is stripped
+ (Jan Kaluza)
+ * use pread()
+
+2013-01-25 18:05 Christos Zoulas <christos@zoulas.com>
+
+ * change mime description size from 64 to 80 to accommodate OOXML.
+
+2013-01-11 14:50 Christos Zoulas <christos@zoulas.com>
+
+ * Warn about inconsistent continuation levels.
+ * Change fsmagic to add a space after it prints.
+
+2013-01-10 21:00 Christos Zoulas <christos@zoulas.com>
+
+ * Make getline public so that file can link against it.
+ Perhaps it is better to rename it, or hide it differently.
+ Fixes builds on platforms that do not provide it.
+
+2013-01-07 16:30 Christos Zoulas <christos@zoulas.com>
+
+ * Add SuS d{,1,2,4,8}, u{,1,2,4,8} and document
+ what long, int, short, etc is (Guy Harris)
+
+2013-01-06 11:20 Christos Zoulas <christos@zoulas.com>
+
+ * add magic_version function and constant
+ * Redo memory allocation and de-allocation.
+ (prevents double frees on non mmap platforms)
+ * Fix bug with name/use having to do with passing
+ found state from the parent to the child and back.
+
+2012-12-19 8:47 Christos Zoulas <christos@zoulas.com>
+
+ * Only print elf capabilities for archs we know (Jan Kaluza)
+
+2012-10-30 19:14 Christos Zoulas <christos@zoulas.com>
+
+ * Add "name" and "use" file types in order to look
+ inside mach-o files.
+
+2012-09-06 10:40 Christos Zoulas <christos@zoulas.com>
+
+ * make --version exit 0 (Matthew Schultz)
+ * add string/T (Jan Kaluza)
+
+2012-08-09 2:15 Christos Zoulas <christos@zoulas.com>
+
+ * add z and t modifiers for our own vasprintf
+ * search for $HOME/.magic.mgc if it is there first
+ * fix reads from a pipe, and preserve errno
+
+2012-05-15 13:12 Christos Zoulas <christos@zoulas.com>
+
+ * use ctime_r, asctime_r
+
+2012-04-06 17:18 Christos Zoulas <christos@zoulas.com>
+
+ * Fixes for indirect offsets to handle apple disk formats
+
+2012-04-03 18:26 Christos Zoulas <christos@zoulas.com>
+
+ * Add windows date field types
+ * More info for windows shortcuts (incomplete)
+
+2012-02-20 17:33 Christos Zoulas <christos@zoulas.com>
+
+ * Fix CDF parsing issues found by CERT's fuzzing tool (Will Dormann)
+
+2011-12-15 12:17 Chris Metcalf <cmetcalf@tilera.com>
+
+ * Support Tilera architectures (tile64, tilepro, tilegx).
+
+2011-12-16 16:33 Reuben Thomas <rrt@sc3d.org>
+
+ * Add magic for /usr/bin/env Perl scripts
+ * Weaken generic script magic to avoid clashing with
+ language-specific magic.
+
+2011-12-08 13:37 Reuben Thomas <rrt@sc3d.org>
+
+ * Simplify if (p) free(p) to free(p).
+
+2011-12-08 13:07 Reuben Thomas <rrt@sc3d.org>
+
+ * Remove hardwired token finding (names.h), turning it into soft
+ magic. Patterns are either anchored regexs or search/8192. English
+ language detection and PL/1 detection have been removed as they
+ were too fragile. -e tokens is still accepted for backwards
+ compatibility.
+ * Move 3ds patterns (which are commented out anyway) into autodesk
+ (they were, oddly, in c-lang).
+
+2011-12-06 00:16 Reuben Thomas <rrt@sc3d.org>
+
+ * Tweak strength of generic hash-bang detectors to be less than
+ specific ones.
+ * Make an inconsistent description of Python scripts consistent.
+
+2011-12-05 23:58 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix minor error in file(1).
+
+2011-11-05 00:00 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix issue #150 (I hope).
+
+2011-09-22 12:57 Christos Zoulas <christos@zoulas.com>
+
+ * Python3 binding fixes from Kelly Anderson
+
+2011-09-20 11:32 Christos Zoulas <christos@zoulas.com>
+
+ * If a string type magic entry is marked as text or binary
+ only match text files against text entries and binary
+ files against binary entries.
+
+2011-09-01 12:12 Christos Zoulas <christos@zoulas.com>
+
+ * Don't wait for any subprocess, just the one we forked.
+
+2011-08-26 16:40 Christos Zoulas <christos@zoulas.com>
+
+ * If the application name is not set in a cdf file, try to see
+ if it has a directory with the application name on it.
+
+2011-08-17 14:32 Christos Zoulas <christos@zoulas.com>
+
+ * Fix ELF lseek(2) madness. Inspired by PR/134 by Jan Kaluza
+
+2011-08-14 09:03 Christos Zoulas <christos@zoulas.com>
+
+ * Don't use variable string formats.
+
+2011-07-12 12:32 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix detection of Zip files (Mantis #128).
+ * Make some minor improvements to file(1).
+ * Rename MIME types for filesystem objects for consistency with
+ xdg-utils. Typically this means that application/x-foo becomes
+ inode/foo, but some names also change slightly, e.g.
+ application/x-character-device becomes inode/chardevice.
+
+2011-05-10 20:57 Christos Zoulas <christos@zoulas.com>
+
+ * fix mingw compilation (Abradoks)
+
+2011-05-10 20:57 Christos Zoulas <christos@zoulas.com>
+
+ * remove patchlevel.h
+ * Fix read past allocated memory caused by double-incrementing
+ a pointer in a loop (reported by Roberto Maar)
+
+2011-03-30 15:45 Christos Zoulas <christos@zoulas.com>
+
+ * Fix cdf string buffer setting (Sven Anders)
+
+2011-03-20 16:35 Christos Zoulas <christos@zoulas.com>
+
+ * Eliminate MAXPATHLEN and use dynamic allocation for
+ path and file buffers.
+
+2011-03-15 18:15 Christos Zoulas <christos@zoulas.com>
+
+ * binary tests on magic entries with masks could spuriously
+ get converted to ascii.
+
+2011-03-12 18:06 Reuben Thomas <rrt@sc3d.org>
+
+ * Improve file.man (remove BUGS, present email addresses consistently).
+
+2011-03-07 19:38 Christos Zoulas <christos@zoulas.com>
+
+ * add lrzip support (from Ville Skytta)
+
+2011-02-10 16:36 Christos Zoulas <christos@zoulas.com>
+
+ * fix CDF bounds checking (Guy Helmer)
+
+2011-02-10 12:03 Christos Zoulas <christos@zoulas.com>
+
+ * add cdf_ctime() that prints a meaningful error when time cannot
+ be converted.
+
+2011-02-02 20:40 Christos Zoulas <christos@zoulas.com>
+
+ * help and version output to stdout.
+
+ * When matching softmagic for ascii files, don't just print
+ the softmagic classification, keep going and print the
+ text classification too. This fixes broken troff files when
+ we moved them from keyword recognition to softmagic
+ (they stopped printing "with CRLF" etc.)
+ Reported by Doug McIlroy.
+
+2011-01-16 19:31 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix two potential buffer overruns in apprentice_list.
+
+2011-01-14 22:33 Reuben Thomas <rrt@sc3d.org>
+
+ * New Python binding in pure Python.
+ * Update libmagic(3).
+
+2011-01-06 21:40 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix Python bindings (including recent Python 3 compatibility
+ update).
+
+2011-01-04 18:43 Reuben Thomas <rrt@sc3d.org>
+
+ * magic/Makefile.am: make it easier to recover from magic build failures.
+ * Fix pstring length specifier parsing to avoid generating invalid
+ magic files.
+ * Add pstring length "J" (for "JPEG") to specify that the length
+ include itself.
+ * Fix JPEG comment parsing at last using pstring/HJ!
+ * Ignore section 5 man pages in doc/.cvsignore.
+
+2010-12-22 13:12 Christos Zoulas <christos@zoulas.com>
+
+ * Add pstring/BHhLl to specify the type of the length of pascal
+ strings.
+
+2010-11-26 18:39 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix "-e soft": it was ignored when softmagic was called
+ during asciimagic.
+ * Improve comments and use "unsigned char" in tar.h/is_tar.c.
+
+2010-11-05 17:26 Reuben Thomas <rrt@sc3d.org>
+
+ * Make bug reporting addresses more visible.
+
+2010-11-01 18:35 Reuben Thomas <rrt@sc3d.org>
+
+ * Add tcl magic from Gustaf Neumann
+
+2010-10-24 10:42 Christos Zoulas <christos@zoulas.com>
+
+ * Fix the whitespace comparing code (Christopher Chittleborough)
+
+2010-10-06 21:05 Christos Zoulas <christos@zoulas.com>
+
+ * allow string/t to work (Jan Kaluza)
+
+2010-09-20 22:11 Reuben Thomas <rrt@sc3d.org>
+
+ * Apply some patches from Ubuntu and Fedora.
+
+2010-09-20 21:16 Reuben Thomas <rrt@sc3d.org>
+
+ * Apply all patches from Debian package 5.04-6 which have not
+ already been applied and are not Debian-specific.
+
+2010-09-20 15:24 Reuben Thomas <rrt@sc3d.org>
+
+ * Minor security fix to softmagic.c (don't use untrusted
+ string as printf format).
+
+2010-07-21 12:20 Christos Zoulas <christos@zoulas.com>
+
+ * MINGW32 portability from LRN
+
+ * Don't warn about escaping magic regex chars when we are in a regex.
+
+2010-07-19 10:55 Christos Zoulas <christos@zoulas.com>
+
+ * Only try to print prpsinfo for core files. (Jan Kaluza)
+
+2010-04-22 12:55 Christos Zoulas <christos@zoulas.com>
+
+ * Try more elf offsets for Debian core files. (Arnaud Giersch)
+
+2010-02-20 15:18 Reuben Thomas <rrt@sc3d.org>
+
+ * Clarify which sort of CDF we mean.
+
+2010-02-14 22:58 Reuben Thomas <rrt@sc3d.org>
+
+ * Re-jig Zip file type magic so that unsupported special
+ Zip types (those with "mimetype" at offset 30) can be
+ recognized.
+
+2010-02-02 21:50 Reuben Thomas <rrt@sc3d.org>
+
+ * Add support for OCF (EPUB) files (application/epub+zip)
+
+2010-01-28 18:25 Christos Zoulas <christos@zoulas.com>
+
+ * Fix core-dump from unbound loop:
+ https://bugzilla.redhat.com/show_bug.cgi?id=533245
+
+2010-01-22 15:45 Christos Zoulas <christos@zoulas.com>
+
+ * print proper mime for crystal reports file
+
+ * print the last summary information of a cdf document, not the
+ first so that nested documents print the right info
+
+2010-01-16 18:42 Charles Longeau <chl@tuxfamily.org>
+
+ * bring back some fixes from OpenBSD:
+ - make gcc2 builds file
+ - fix typos in a magic file comment
+
+2009-11-17 18:35 Christos Zoulas <christos@zoulas.com>
+
+ * ctime/asctime can return NULL on some OS's although
+ they should not (Toshit Antani)
+
+2009-09-14 13:49 Christos Zoulas <christos@zoulas.com>
+
+ * Centralize magic path handling routines and remove the
+ special-casing from file.c so that the python module for
+ example comes up with the same magic path (Fixes ~/.magic
+ handling) (from Gab)
+
+2009-09-11 23:38 Reuben Thomas <rrt@sc3d.org>
+
+ * When magic argument is a directory, read the files in
+ strcmp-sorted order (fixes Debian bug #488562 and our own FIXME).
+
+2009-09-11 13:11 Reuben Thomas <rrt@sc3d.org>
+
+ * Combine overlapping epoc and psion magic files into one (epoc).
+
+ * Add some more EPOC MIME types.
+
+2009-08-19 15:55 Christos Zoulas <christos@zoulas.com>
+
+ * Fix 3 bugs (From Ian Darwin):
+ - file_showstr could move one past the end of the array
+ - parse_apple did not nul terminate the string in the overflow case
+ - parse_mime truncated the wrong string in the overflow case
+
+2009-08-12 12:28 Robert Byrnes <byrnes@wildpumpkin.net>
+
+ * Include Localstuff when compiling magic.
+
+2009-07-15 10:05 Christos Zoulas <christos@zoulas.com>
+
+ * Fix logic for including mygetopts.h
+
+ * Make cdf.c compile again with debugging
+
+ * Add the necessary field handling for crystal reports files to work
+
+2009-06-23 01:34 Reuben Thomas <rrt@sc3d.org>
+
+ * Stop "(if" identifying Lisp files, that's plain dumb!
+
+2009-06-09 22:13 Reuben Thomas <rrt@sc3d.org>
+
+ * Add a couple of missing MP3 MIME types.
+
+2009-05-27 23:00 Reuben Thomas <rrt@sc3d.org>
+
+ * Add full range of hash-bang tests for Python and Ruby.
+
+ * Add MIME types for Python and Ruby scripts.
+
+2009-05-13 10:44 Christos Zoulas <christos@zoulas.com>
+
+ * off by one in parsing hw capabilities in elf
+ (Cheng Renquan)
+
+2009-05-08 13:40 Christos Zoulas <christos@zoulas.com>
+
+ * lint fixes and more from NetBSD
+
+2009-05-06 10:25 Christos Zoulas <christos@zoulas.com>
+
+ * Avoid null dereference in cdf code (Drew Yao)
+
+ * More cdf bounds checks and overflow checks
+
+2009-05-01 18:37 Christos Zoulas <christos@zoulas.com>
+
+ * Buffer overflow fixes from Drew Yao
+
+2009-04-30 17:10 Christos Zoulas <christos@zoulas.com>
+
+ * Fix more cdf lossage. All the documents I have
+ right now print the correct information.
+
+2009-03-27 18:43 Christos Zoulas <christos@zoulas.com>
+
+ * don't print \012- separators in the same magic entry
+ if it consists of multiple magic printing lines.
+
+2009-03-23 10:20 Christos Zoulas <christos@zoulas.com>
+
+ * Avoid file descriptor leak in compress code from
+ (Daniel Novotny)
+
+2009-03-18 16:50 Christos Zoulas <christos@zoulas.com>
+
+ * Allow escaping of relation characters, so that we can say \^[A-Z]
+ and the ^ is not eaten as a relation char.
+
+ * Fix troff and fortran to their previous glory using
+ regex. This was broken since their removel from ascmagic.
+
+2009-03-10 16:50 Christos Zoulas <christos@zoulas.com>
+
+ * don't use strlen in strndup() (Toby Peterson)
+
+2009-03-10 7:45 Christos Zoulas <christos@zoulas.com>
+
+ * avoid c99 syntax.
+
+2009-02-23 15:45 Christos Zoulas <christos@zoulas.com>
+
+ * make the cdf code use the buffer first if available,
+ and then the fd code.
+
+2009-02-13 13:45 Christos Zoulas <christos@zoulas.com>
+
+ * look for struct option to determine if getopt.h is usable for IRIX.
+
+ * sanitize cdf document strings
+
+2009-02-04 13:25 Christos Zoulas <christos@zoulas.com>
+
+ * fix OS/2 warnings.
+
+2008-12-12 15:50 Christos Zoulas <christos@zoulas.com>
+
+ * fix initial offset calculation for non 4K sector files
+
+ * add loop limits to avoid DoS attacks by constructing
+ looping sector references.
+
+2008-12-03 13:05 Christos Zoulas <christos@zoulas.com>
+
+ * fix memory botches on cdf file parsing.
+
+ * exit with non-zero value for any error, not just for the last
+ file processed.
+
+2008-11-09 20:42 Charles Longeau <chl@tuxfamily.org>
+
+ * Replace all str{cpy,cat} functions with strl{cpy,cat}
+ * Ensure that strl{cpy,cat} are included in libmagic,
+ as needed.
+
+2008-11-06 18:18 Christos Zoulas <christos@zoulas.com>
+
+ * Handle ID3 format files.
+
+2008-11-06 23:00 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix --mime, --mime-type and --mime-encoding under new scheme.
+
+ * Rename "ascii" to "text" and add "encoding" test.
+
+ * Return a precise ("utf-16le" or "utf-16be") MIME charset for
+ UTF-16.
+
+ * Fix error in comment caused by automatic indentation adding
+ words!
+
+2008-11-06 10:35 Christos Zoulas <christos@astron.com>
+
+ * use memchr instead of strchr because the string
+ might not be NUL terminated (Scott MacVicar)
+
+2008-11-03 07:31 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix a printf with a non-literal format string.
+
+ * Fix formatting and punctuation of help for "--apple".
+
+2008-10-30 11:00 Reuben Thomas <rrt@sc3d.org>
+
+ * Correct words counts in comments of struct magic.
+
+ * Fix handle_annotation to allow both Apple and MIME types to be
+ printed, and to return correct code if MIME type is
+ printed (1, not 0) or if there's an error (-1 not 1).
+
+ * Fix output of charset for MIME type (precede with semi-colon;
+ fixes Debian bug #501460).
+
+ * Fix potential attacks via conversion specifications in magic
+ strings.
+
+ * Add a FIXME for Debian bug #488562 (magic files should be
+ read in a defined order, by sorting the names).
+
+2008-10-18 16:45 Christos Zoulas <christos@astron.com>
+
+ * Added APPLE file creator/type
+
+2008-10-12 10:20 Christos Zoulas <christos@astron.com>
+
+ * Added CDF parsing
+
+2008-10-09 16:40 Christos Zoulas <christos@astron.com>
+
+ * filesystem and msdos patches (Joerg Jenderek)
+
+2008-10-09 13:20 Christos Zoulas <christos@astron.com>
+
+ * correct --exclude documentation issues: remove troff and fortran
+ and rename "token" to "tokens". (Randy McMurchy)
+
+2008-10-01 10:30 Christos Zoulas <christos@astron.com>
+
+ * Read ~/.magic in addition to the default magic file not instead
+ of, as documented in the man page.
+
+2008-09-10 21:30 Reuben Thomas <rrt@sc3d.org>
+
+ * Comment out graphviz patterns, as they match too many files.
+
+2008-08-30 12:54 Christos Zoulas <christos@astron.com>
+
+ * Don't eat trailing \n in magic enties.
+
+ * Cast defines to allow compilation using a c++ compiler.
+
+2008-08-25 23:56 Reuben Thomas <rrt@sc3d.org>
+
+ * Add text/x-lua MIME type for Lua scripts.
+
+ * Escape { in regex in graphviz patterns.
+
+2008-07-26 00:59 Reuben Thomas <rrt@sc3d.org>
+
+ * Add MIME types for special files.
+
+ * Use access to give more accurate information for files that
+ can't be opened.
+
+ * Add a TODO list.
+
+2008-07-02 11:15 Christos Zoulas <christos@astron.com>
+
+ * add !:strength op to adjust magic strength (experimental)
+
+2008-06-16 21:41 Reuben Thomas <rrt@sc3d.org>
+
+ * Fix automake error in configure.ac.
+
+ * Add MIME type for Psion Sketch files.
+
+2008-06-05 08:59 Christos Zoulas <christos@astron.com>
+
+ * Don't print warnings about bad namesize in stripped
+ binaries with PT_NOTE is still there, and the actual
+ note is gone (Jakub Jelinek)
+
+2008-05-28 15:12 Robert Byrnes <byrnes@wildpumpkin.net>
+
+ * magic/Magdir/elf:
+ Note invalid byte order for little-endian SPARC32PLUS.
+ Add SPARC V9 vendor extensions and memory model.
+
+ * src/elfclass.h:
+ Pass target machine to doshn (for Solaris hardware capabilities).
+
+ * src/readelf.c (doshn):
+ Add support for Solaris hardware/software capabilities.
+
+ * src/readelf.h:
+ Ditto.
+
+ * src/vasprintf.c (dispatch):
+ Add support for ll modifier.
+
+2008-05-16 10:25 Christos Zoulas <christos@astron.com>
+
+ * Fix compiler warnings.
+
+ * remove stray printf, and fix a vprintf bug. (Martin Dorey)
+
+2008-05-06 00:13 Robert Byrnes <byrnes@wildpumpkin.net>
+
+ * src/Makefile.am:
+ Ensure that getopt_long and [v]asprintf are included in libmagic,
+ as needed.
+
+ Remove unnecessary EXTRA_DIST.
+
+ * src/Makefile.in:
+ Rerun automake.
+
+ * src/vasprintf.c (dispatch):
+ Fix variable precision bug: be sure to step past '*'.
+
+ * src/vasprintf.c (core):
+ Remove unreachable code.
+
+ * src/apprentice.c (set_test_type):
+ Add cast to avoid compiler warning.
+
+2008-04-22 23:45 Christos Zoulas <christos@astron.com>
+
+ * Add magic submission guidelines (Abel Cheung)
+
+ * split msdos and windows magic (Abel Cheung)
+
+2008-04-04 11:00 Christos Zoulas <christos@astron.com>
+
+ * >= <= is not supported, so fix the magic and warn about it.
+ reported by: Thien-Thi Nguyen <ttn@gnuvola.org>
+
+2008-03-27 16:16 Robert Byrnes <byrnes@wildpumpkin.net>
+
+ * src/readelf.c (donote):
+ ELF core file command name/line bug fixes and enhancements:
+
+ Try larger offsets first to avoid false matches
+ from earlier data that happen to look like strings;
+ this primarily affected SunOS 5.x 32-bit Intel core files.
+
+ Add support for command line (instead of just short name)
+ for SunOS 5.x.
+
+ Add information about NT_PSINFO for SunOS 5.x.
+
+ Only trim whitespace from end of command line.
+
+2007-02-11 01:36 Reuben Thomas <rrt@sc3d.org>
+
+ * Change strength of ! from MULT to 0, as it matches almost
+ anything (Reuben Thomas)
+
+ * Debian fixes (Reuben Thomas)
+
+2007-02-11 00:17 Reuben Thomas <rrt@sc3d.org>
+
+ * Clarify UTF-8 BOM message (Reuben Thomas)
+
+ * Add HTML comment to token list in names.h
+
+2007-02-04 15:50 Christos Zoulas <christos@astron.com>
+
+ * Debian fixes (Reuben Thomas)
+
+2007-02-04 11:31 Christos Zoulas <christos@astron.com>
+
+ * !:mime annotations in magic files (Reuben Thomas)
+
+2007-01-29 15:35 Christos Zoulas <christos@astron.com>
+
+ * zero out utime/utimes structs (Gavin Atkinson)
+
+2007-01-26 13:45 Christos Zoulas <christos@astron.com>
+
+ * reduce writable data from Diego "Flameeyes" Petten
+
+2007-12-28 15:06 Christos Zoulas <christos@astron.com>
+
+ * strtof detection
+
+ * remove bogus regex magic that could cause a DoS
+
+ * better mismatch version message
+
+2007-12-27 11:35 Christos Zoulas <christos@astron.com>
+
+ * bring back some fixes from OpenBSD
+
+ * treat ELF dynamic objects as executables
+
+ * fix gcc warnings
+
+2007-12-01 19:55 Christos Zoulas <christos@astron.com>
+
+ * make sure we have zlib.h and libz to compile the builtin
+ decompress code
+
+2007-10-28 20:48 Christos Zoulas <christos@astron.com>
+
+ * float and double magic support (Behan Webster)
+
+2007-10-28 20:48 Christos Zoulas <christos@astron.com>
+
+ * Convert fortran to a soft test (Reuben Thomas)
+
+2007-10-23 5:25 Christos Zoulas <christos@astron.com>
+
+ * Add --with-filename, and --no-filename (Reuben Thomas)
+
+2007-10-23 3:59 Christos Zoulas <christos@astron.com>
+
+ * Rest of the mime split (Reuben Thomas)
+
+ * Make usage message generated from the flags so that
+ they stay consistent (Reuben Thomas)
+
+2007-10-20 3:06 Christos Zoulas <christos@astron.com>
+
+ * typo in comment, missing ifdef QUICK, remove unneeded code
+ (Charles Longeau)
+
+2007-10-17 3:33 Christos Zoulas <christos@astron.com>
+
+ * Fix problem printing -\012 in some entries
+
+ * Separate magic type and encoding flags (Reuben Thomas)
+
+2007-10-09 3:55 Christos Zoulas <christos@astron.com>
+
+ * configure fix for int64 and strndup (Reuben Thomas)
+
+2007-09-26 4:45 Christos Zoulas <christos@astron.com>
+
+ * Add magic_descriptor() function.
+
+ * Fix regression in elf reading code where the core name was
+ not being printed.
+
+ * Don't convert NUL's to spaces in {l,b}estring16 (Daniel Dawson)
+
+2007-08-19 6:30 Christos Zoulas <christos@astron.com>
+
+ * Make mime format consistent so that it can
+ be easily parsed:
+ mimetype [charset=character-set] [encoding=encoding-mime-type]
+
+ Remove spurious extra text from some MIME type printouts
+ (mostly in is_tar).
+
+ Fix one case where -i produced nothing at all (for a 1-byte file,
+ which is now classed as application/octet-stream).
+
+ Remove 7/8bit classifications, since they were arbitrary
+ and not based on the file data.
+
+ This work was done by Reuben Thomas
+
+2007-05-24 10:00 Christos Zoulas <christos@astron.com>
+
+ * Fix another integer overflow (Colin Percival)
+
+2007-03-26 13:58 Christos Zoulas <christos@astron.com>
+
+ * make sure that all of struct magic_set is initialized appropriately
+ (Brett)
+
+2007-03-25 17:44 Christos Zoulas <christos@astron.com>
+
+ * reset left bytes in the buffer (Dmitry V. Levin)
+
+ * compilation failed with COMPILE_ONLY and ENABLE_CONDITIONALS
+ (Peter Avalos)
+
+2007-03-15 10:51 Christos Zoulas <christos@astron.com>
+
+ * fix fortran and nroff reversed tests (Dmitry V. Levin)
+
+ * fix exclude option (Dmitry V. Levin)
+
+2007-02-08 17:30 Christos Zoulas <christos@astron.com>
+
+ * fix integer underflow in file_printf which can lead to
+ to exploitable heap overflow (Jean-Sebastien Guay-Lero)
+
+2007-02-05 11:35 Christos Zoulas <christos@astron.com>
+
+ * make socket/pipe reading more robust
+
+2007-01-25 16:01 Christos Zoulas <christos@astron.com>
+
+ * Centralize all the tests in file_buffer.
+
+ * Add exclude flag.
+
+2007-01-18 05:29 Anon Ymous <do@not.spam.me>
+
+ * Move the "type" detection code from parse() into its own table
+ driven routine. This avoids maintaining multiple lists in
+ file.h.
+
+ * Add an optional conditional field (ust before the type field).
+ This code is wrapped in "#ifdef ENABLE_CONDITIONALS" as it is
+ likely to go away.
+
+2007-01-16 23:24 Anon Ymous <do@not.spam.me>
+
+ * Fix an initialization bug in check_mem().
+
+2007-01-16 14:58 Anon Ymous <do@not.spam.me>
+
+ * Add a "default" type to print a message if nothing previously
+ matched at that level or since the last default at that
+ level. This is useful for setting up switch-like statements.
+ It can also be used to do if/else constructions without a
+ redundant second test.
+
+ * Fix the "x" special case test so that one can test for that
+ string with "=x".
+
+ * Allow "search" to search the entire buffer if the "/N"
+ search count is missing.
+
+ * Make "regex" work! It now starts its search at the
+ specified offset and takes an (optional) "/N" line count to
+ specify the search range; otherwise it searches to the end
+ of the file. The match is now grabbed correctly for format
+ strings and the offset set to the end of the match.
+
+ * Add a "/s" flag to "regex" and "search" to set the offset to
+ the start of the match. By default the offset is set to the
+ end of the match, as it is with other tests. This is mostly
+ useful for "regex".
+
+ * Make "search", "string" and "pstring" use the same
+ file_strncmp() routine so that they support the same flags;
+ "bestring16" and "lestring16" call the same routine, but
+ with flags = 0. Also add a "/C" flag (in analogy to "/c")
+ to ignore the case on uppercase (lowercase) characters in
+ the test string.
+
+ * Strict adherence to C style string escapes. A warnings are
+ printed when compiling. Note: previously "\a" was
+ incorrectly translated to 'a' instead of an <alert> (i.e.,
+ BELL, typically 0x07).
+
+ * Make this compile with "-Wall -Wextra" and all the warning
+ flags used with WARNS=4 in the NetBSD source. Also make it
+ pass lint.
+
+ * Many "cleanups" and hopefully not too many new bugs!
+
+2007-01-16 14:56 Anon Ymous <do@not.spam.me>
+
+ * make several more files compile with gcc warnings
+ on and also make them pass lint.
+
+2007-01-16 14:54 Anon Ymous <do@not.spam.me>
+
+ * fix a puts()/putc() usage goof in file.c
+
+ * make file.c compile with gcc warnings and pass lint
+
+2006-12-11 16:49 Christos Zoulas <christos@astron.com>
+
+ * fix byteswapping issue
+
+ * report the number of bytes we tried to
+ allocate when allocation fails
+
+ * add a few missed cases in the strength routine
+
+2006-12-08 16:32 Christos Zoulas <christos@astron.com>
+
+ * store and print the line number of the magic
+ entry for debugging.
+
+ * if the magic entry did not print anything,
+ don't treat it as a match
+
+ * change the magic strength algorithm to take
+ into account the relationship op.
+
+ * fix a bug in search where we could accidentally
+ return a match.
+
+ * propagate the error return from match to
+ file_softmagic.
+
+2006-11-25 13:35 Christos Zoulas <christos@astron.com>
+
+ * Don't store the current offset in the magic
+ struct, because it needs to be restored and
+ it was not done properly all the time. Bug
+ found by: Arkadiusz Miskiewicz
+
+ * Fix problem in the '\0' separator; and don't
+ print it as an additional separator; print
+ it as the only separator.
+
+2006-11-17 10:51 Christos Zoulas <christos@astron.com>
+
+ * Added a -0 option to print a '\0' separator
+ Etienne Buira <etienne.buira@free.fr>
+
+2006-10-31 15:14 Christos Zoulas <christos@astron.com>
+
+ * Check offset before copying (Mike Frysinger)
+
+ * merge duplicated code
+
+ * add quad date support
+
+ * make sure that we nul terminate desc (Ryoji Kanai)
+
+ * don't process elf notes multiple times
+
+ * allow -z to report empty compressed files
+
+ * use calloc to initialize the ascii buffers (Jos van den Oever)
+
+2006-06-08 11:11 Christos Zoulas <christos@astron.com>
+
+ * QNX fixes (Mike Gorchak)
+
+ * Add quad support.
+
+ * FIFO checks (Dr. Werner Fink)
+
+ * Linux ELF fixes (Dr. Werner Fink)
+
+ * Magic format checks (Dr. Werner Fink)
+
+ * Magic format function improvent (Karl Chen)
+
+2006-05-03 11:11 Christos Zoulas <christos@astron.com>
+
+ * Pick up some elf changes and some constant fixes from SUSE
+
+ * Identify gnu tar vs. posix tar
+
+ * When keep going, don't print spurious newlines (Radek Vokal)
+
+2006-04-01 12:02 Christos Zoulas <christos@astron.com>
+
+ * Use calloc instead of malloc (Mike Frysinger)
+
+ * Fix configure script to detect wctypes.h (Mike Frysinger)
+
+2006-03-02 16:06 Christos Zoulas <christos@astron.com>
+
+ * Print empty if the file is (Mike Frysinger)
+
+ * Don't try to read past the end of the buffer (Mike Frysinger)
+
+ * Sort magic entries by strength [experimental]
+
+2005-11-29 13:26 Christos Zoulas <christos@astron.com>
+
+ * Use iswprint() to convert the output string.
+ (Bastien Nocera)
+
+2005-10-31 8:54 Christos Zoulas <christos@astron.com>
+
+ * Fix regression where the core info was not completely processed
+ (Radek Vokal)
+
+2005-10-20 11:15 Christos Zoulas <christos@astron.com>
+
+ * Middle Endian magic (Diomidis Spinellis)
+
+2005-10-17 11:15 Christos Zoulas <christos@astron.com>
+
+ * Open with O_BINARY for CYGWIN (Corinna Vinschen)
+
+ * Don't close stdin (Arkadiusz Miskiewicz)
+
+ * Look for note sections in non executables.
+
+2005-09-20 13:33 Christos Zoulas <christos@astron.com>
+
+ * Don't print SVR4 Style in core files multiple times
+ (Radek Vokal)
+
+2005-08-27 04:09 Christos Zoulas <christos@astron.com>
+
+ * Cygwin changes Corinna Vinschen
+
+2005-08-18 09:53 Christos Zoulas <christos@astron.com>
+
+ * Remove erroreous mention of /etc/magic in the file man page
+ This is gentoo bug 101639. (Mike Frysinger)
+
+ * Cross-compile support and detection (Mike Frysinger)
+
+2005-08-12 10:17 Christos Zoulas <christos@astron.com>
+
+ * Add -h flag and dereference symlinks if POSIXLY_CORRECT
+ is set.
+
+2005-07-29 13:57 Christos Zoulas <christos@astron.com>
+
+ * Avoid search and regex buffer overflows (Kelledin)
+
+2005-07-12 11:48 Christos Zoulas <christos@astron.com>
+
+ * Provide stub implementations for {v,}nsprintf() for older
+ OS's that don't have them.
+ * Change mbstate_t autoconf detection macro from AC_MBSTATE_T
+ to AC_TYPE_MBSTATE_T.
+
+2005-06-25 11:48 Christos Zoulas <christos@astron.com>
+
+ * Dynamically allocate the string buffers and make the
+ default read size 256K.
+
+2005-06-01 00:00 Joerg Sonnenberger <joerg@britannica.bec.de>
+
+ * Dragonfly ELF note support
+
+2005-03-14 00:00 Giuliano Bertoletti <gb@symbolic.it>
+
+ * Avoid NULL pointer dereference in time conversion.
+
+2005-03-06 00:00 Joerg Walter <jwalt@mail.garni.ch>
+
+ * Add indirect magic offset support, and search mode.
+
+2005-01-12 00:00 Stepan Kasal <kasal@ucw.cz>
+
+ * src/ascmagic.c (file_ascmagic): Fix three bugs about text files:
+ If a CRLF text file happens to have CR at offset HOWMANY - 1
+ (currently 0xffff), it should not be counted as CR line
+ terminator.
+ If a line has length exactly MAXLINELEN, it should not yet be
+ treated as a ``very long line'', as MAXLINELEN is ``longest sane
+ line length''.
+ With CRLF, the line length was not computed correctly, and even
+ lines of length MAXLINELEN - 1 were treated as ``very long''.
+
+2004-12-07 14:15 Christos Zoulas <christos@astron.com>
+
+ * bzip2 needs a lot of input buffer space on some files
+ before it can begin uncompressing. This makes file -z
+ fail on some bz2 files. Fix it by giving it a copy of
+ the file descriptor to read as much as it wants if we
+ have access to it. <christos@astron.com>
+
+2004-11-24 12:39 Christos Zoulas <christos@astron.com>
+
+ * Stack smash fix, and ELF more conservative reading.
+ Jakub Bogusz <qboosh@pld-linux.org>
+
+2004-11-20 18:50 Christos Zoulas <christos@astron.com>
+
+ * New FreeBSD version parsing code:
+ Jon Noack <noackjr@alumni.rice.edu>
+
+ * Hackish support for ucs16 strings <christos@astron.com>
+
+2004-11-13 03:07 Christos Zoulas <christos@astron.com>
+
+ * print the file name and line number in syntax errors.
+
+2004 10-12 10:50 Christos Zoulas <christos@astron.com>
+
+ * Fix stack overwriting on 0 length strings: Tim Waugh
+ <twaugh@redhat.com> Ned Ludd <solar@gentoo.org>
+
+2004-09-27 11:30 Christos Zoulas <christos@astron.com>
+
+ * Remove 3rd and 4th copyright clause; approved by Ian Darwin.
+
+ * Fix small memory leaks; caught by: Tamas Sarlos
+ <stamas@csillag.ilab.sztaki.hu>
+
+2004-07-24 16:33 Christos Zoulas <christos@astron.com>
+
+ * magic.mime update Danny Milosavljevic <danny.milo@gmx.net>
+
+ * FreeBSD version update Oliver Eikemeier <eikemeier@fillmore-labs.com>
+
+ * utime/utimes detection Ian Lance Taylor <ian@wasabisystems.com>
+
+ * errors reading elf magic Jakub Bogusz <qboosh@pld-linux.org>
+
+2004-04-12 10:55 Christos Zoulas <christos@astron.com>
+
+ * make sure that magic formats match magic types during compilation
+
+ * fix broken sgi magic file
+
+2004-04-06 20:36 Christos Zoulas <christos@astron.com>
+
+ * detect present of mbstate_t Petter Reinholdtsen <pere@hungry.com>
+
+ * magic fixes
+
+2004-03-22 15:25 Christos Zoulas <christos@astron.com>
+
+ * Lots of mime fixes
+ (Joerg Ostertag) <ostertag@rechengilde.de>
+
+ * FreeBSD ELF version handling
+ (Edwin Groothuis) <edwin@mavetju.org>
+
+ * correct cleanup in all cases; don't just close the file.
+ (Christos Zoulas) <christos@astron.com>
+
+ * add gettext message catalogue support
+ (Michael Piefel) <piefel@debian.org>
+
+ * better printout for unreadable files
+ (Michael Piefel) <piefel@debian.org>
+
+ * compensate for missing MAXPATHLEN
+ (Michael Piefel) <piefel@debian.org>
+
+ * add wide character string length computation
+ (Michael Piefel) <piefel@debian.org>
+
+ * Avoid infinite loops caused by bad elf alignments
+ or name and description note sizes. Reported by
+ (Mikael Magnusson) <mmikael@comhem.se>
+
+2004-03-09 13:55 Christos Zoulas <christos@astron.com>
+
+ * Fix possible memory leak on error and add missing regfree
+ (Dmitry V. Levin) <ldv@altlinux.org>
+
+2003-12-23 12:12 Christos Zoulas <christos@astron.com>
+
+ * fix -k flag (Maciej W. Rozycki)
+
+2003-11-18 14:10 Christos Zoulas <christos@astron.com>
+
+ * Try to give us much info as possible on corrupt elf files.
+ (Willy Tarreau) <willy@w.ods.org>
+ * Updated python bindings (Brett Funderburg)
+ <brettf@deepfile.com>
+
+2003-11-11 15:03 Christos Zoulas <christos@astron.com>
+
+ * Include file.h first, because it includes config.h
+ breaks largefile test macros otherwise.
+ (Paul Eggert <eggert@CS.UCLA.EDU> via
+ Lars Hecking <lhecking@nmrc.ie>)
+
+2003-10-14 21:39 Christos Zoulas <christos@astron.com>
+
+ * Python bindings (Brett Funderburg) <brettf@deepfile.com>
+ * Don't lookup past the end of the buffer
+ (Chad Hanson) <chanson@tcs-sec.com>
+ * Add MAGIC_ERROR and api on magic_errno()
+
+2003-10-08 12:40 Christos Zoulas <christos@astron.com>
+
+ * handle error conditions from compile as fatal
+ (Antti Kantee) <pooka@netbsd.org>
+ * handle magic filename parsing sanely
+ * more magic fixes.
+ * fix a memory leak (Illes Marton) <illes.marton@balabit.hu>
+ * describe magic file handling
+ (Bryan Henderson) <bryanh@giraffe-data.com>
+
+2003-09-12 15:09 Christos Zoulas <christos@astron.com>
+
+ * update magic files.
+ * remove largefile support from file.h; it breaks things on most OS's
+
+2003-08-10 10:25 Christos Zoulas <christos@astron.com>
+
+ * fix unmapping'ing of mmaped files.
+
+2003-07-10 12:03 Christos Zoulas <christos@astron.com>
+
+ * don't exit with -1 on error; always exit 1 (Marty Leisner)
+ * restore utimes code.
+
+2003-06-10 17:03 Christos Zoulas <christos@astron.com>
+
+ * make sure we don't access uninitialized memory.
+ * pass lint
+ * #ifdef __cplusplus in magic.h
+
+2003-05-25 19:23 Christos Zoulas <christos@astron.com>
+
+ * rename cvs magic file to revision to deal with
+ case insensitive filesystems.
+
+2003-05-23 17:03 Christos Zoulas <christos@astron.com>
+
+ * documentation fixes from Michael Piefel <piefel@debian.org>
+ * magic fixes (various)
+ * revert basename magic in .mgc name determination
+ * buffer protection in uncompress,
+ signness issues,
+ close files
+ Maciej W. Rozycki <macro@ds2.pg.gda.pl
+
+2003-04-21 20:12 Christos Zoulas <christos@astron.com>
+
+ * fix zsh magic
+
+2003-04-04 16:59 Christos Zoulas <christos@astron.com>
+
+ * fix operand sort order in string.
+
+2003-04-02 17:30 Christos Zoulas <christos@astron.com>
+
+ * cleanup namespace in magic.h
+
+2003-04-02 13:50 Christos Zoulas <christos@astron.com>
+
+ * Magic additions (Alex Ott)
+ * Fix bug that broke VPATH compilation (Peter Breitenlohner)
+
+2003-03-28 16:03 Christos Zoulas <christos@astron.com>
+
+ * remove packed attribute from magic struct.
+ * make the magic struct properly aligned.
+ * bump version number of compiled files to 2.
+
+2003-03-27 13:10 Christos Zoulas <christos@astron.com>
+
+ * separate tar detection and run it before softmagic.
+ * fix reversed symlink test.
+ * fix version printing.
+ * make separator a string instead of a char.
+ * update manual page and sort options.
+
+2003-03-26 11:00 Christos Zoulas <christos@astron.com>
+
+ * Pass lint
+ * make NULL in magic_file mean stdin
+ * Fix "-" argument to file to pass NULL to magic_file
+ * avoid pointer casts by using memcpy
+ * rename magic_buf -> magic_buffer
+ * keep only the first error
+ * manual page: new sentence, new line
+ * fix typo in api function (magic_buf -> magic_buffer)
diff --git a/node_modules/mmmagic/deps/libmagic/INSTALL b/node_modules/mmmagic/deps/libmagic/INSTALL
new file mode 100644
index 0000000..7d1c323
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/node_modules/mmmagic/deps/libmagic/MAINT b/node_modules/mmmagic/deps/libmagic/MAINT
new file mode 100644
index 0000000..b881615
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/MAINT
@@ -0,0 +1,44 @@
+$File: MAINT,v 1.10 2008/02/05 19:08:11 christos Exp $
+
+Maintenance notes:
+
+I am continuing to maintain the file command. I welcome your help,
+but to make my life easier I'd like to request the following:
+
+- Do not distribute changed versions.
+
+People trying to be helpful occasionally put up their hacked versions
+of the file command for anonymous FTP, and people all over the
+world get copies of the hacked versions. Within a day or two I am
+getting email from around the world asking me why "my" file command
+won't compile!!! Needless to say this detracts from the limited
+time I have available to work on the actual software. Therefore I
+ask you again to please NOT distribute your changed version. If
+you need to make changes, please add a patch file next to the
+distribution tar, and a README file that clearly explains what you
+are trying to fix.
+
+Thank you for your assistance and cooperation.
+
+Code Overview
+
+This is a rough idea of the control flow from the main program:
+
+file.c main()
+file.c process (called for each file)
+ printf file name
+magic.c magic_file()
+fsmagic.c file_fsmagic()
+ (handles statbuf modes for DEV)
+ (handles statbuf modes for executable &c.
+ reads data from file.
+funcs.c: file_buffer()
+compress.c file_zmagic()
+is_tar.c file_is_tar()
+softmagic.c file_softmagic()
+ match() - looks for match against main magic database
+ascmagic.c file_ascmagic()
+readelf.c file_tryelf()
+ "unknown"
+
+Christos Zoulas (see README for email address)
diff --git a/node_modules/mmmagic/deps/libmagic/NEWS b/node_modules/mmmagic/deps/libmagic/NEWS
new file mode 100644
index 0000000..939a279
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/NEWS
@@ -0,0 +1 @@
+See ChangeLog. \ No newline at end of file
diff --git a/node_modules/mmmagic/deps/libmagic/README b/node_modules/mmmagic/deps/libmagic/README
new file mode 100644
index 0000000..bb8186f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/README
@@ -0,0 +1,161 @@
+## README for file(1) Command ##
+
+ @(#) $File: README,v 1.50 2016/04/16 22:40:54 christos Exp $
+
+Mailing List: file@mx.gw.com
+Mailing List archives: http://mx.gw.com/pipermail/file/
+Bug tracker: http://bugs.gw.com/
+E-mail: christos@astron.com
+
+[![Build Status](https://travis-ci.org/file/file.png?branch=master)](https://travis-ci.org/file/file)
+
+Phone: Do not even think of telephoning me about this program. Send cash first!
+
+This is Release 5.x of Ian Darwin's (copyright but distributable)
+file(1) command, an implementation of the Unix File(1) command.
+It knows the 'magic number' of several thousands of file types.
+This version is the standard "file" command for Linux,
+*BSD, and other systems. (See "patchlevel.h" for the exact release number).
+
+You can download the latest version of the original sources for file from:
+
+ ftp://ftp.astron.com/pub/file/
+
+A public read-only git repository of the same sources is available at:
+
+ https://github.com/file/file
+
+The major changes for 5.x are CDF file parsing, indirect magic, name/use
+(recursion) and overhaul in mime and ascii encoding handling.
+
+The major feature of 4.x is the refactoring of the code into a library,
+and the re-write of the file command in terms of that library. The library
+itself, libmagic can be used by 3rd party programs that wish to identify
+file types without having to fork() and exec() file. The prime contributor
+for 4.0 was Mans Rullgard.
+
+UNIX is a trademark of UNIX System Laboratories.
+
+The prime contributor to Release 3.8 was Guy Harris, who put in megachanges
+including byte-order independence.
+
+The prime contributor to Release 3.0 was Christos Zoulas, who put
+in hundreds of lines of source code changes, including his own
+ANSIfication of the code (I liked my own ANSIfication better, but
+his (__P()) is the "Berkeley standard" way of doing it, and I wanted UCB
+to include the code...), his HP-like "indirection" (a feature of
+the HP file command, I think), and his mods that finally got the
+uncompress (-z) mode finished and working.
+
+This release has compiled in numerous environments; see PORTING
+for a list and problems.
+
+This fine freeware file(1) follows the USG (System V) model of the file
+command, rather than the Research (V7) version or the V7-derived 4.[23]
+Berkeley one. That is, the file /etc/magic contains much of the ritual
+information that is the source of this program's power. My version
+knows a little more magic (including tar archives) than System V; the
+/etc/magic parsing seems to be compatible with the (poorly documented)
+System V /etc/magic format (with one exception; see the man page).
+
+In addition, the /etc/magic file is built from a subdirectory
+for easier(?) maintenance. I will act as a clearinghouse for
+magic numbers assigned to all sorts of data files that
+are in reasonable circulation. Send your magic numbers,
+in magic(5) format please, to the maintainer, Christos Zoulas.
+
+COPYING - read this first.
+README - read this second (you are currently reading this file).
+INSTALL - read on how to install
+src/localtime_r.c
+src/magic.c
+src/magic.h
+src/mygetopt.h
+src/newtest2.c
+src/newtest3.c
+src/pread.c
+src/print.c
+src/readcdf.c
+src/readelf.c
+src/readelf.h
+src/regex.c
+src/regex2.c
+src/softmagic.c
+src/strcasestr.c
+src/strlcat.c
+src/strlcpy.c
+src/strndup.c
+src/tar.h
+src/teststrchr.c
+src/vasprintf.c
+src/x.c
+src/apprentice.c - parses /etc/magic to learn magic
+src/apptype.c - used for OS/2 specific application type magic
+src/ascmagic.c - third & last set of tests, based on hardwired assumptions.
+src/asctime_r.c - replacement for OS's that don't have it.
+src/asprintf.c - replacement for OS's that don't have it.
+src/asctime_r.c - replacement for OS's that don't have it.
+src/asprintf.c - replacement for OS's that don't have it.
+src/cdf.[ch] - parser for Microsoft Compound Document Files
+src/cdf_time.c - time converter for CDF.
+src/compress.c - handles decompressing files to look inside.
+src/ctime_r.c - replacement for OS's that don't have it.
+src/der.[ch] - parser for Distinguished Encoding Rules
+src/dprintf.c - replacement for OS's that don't have it.
+src/elfclass.h - common code for elf 32/64.
+src/encoding.c - handles unicode encodings
+src/file.c - the main program
+src/file.h - header file
+src/file_opts.h - list of options
+src/fmtcheck.c - replacement for OS's that don't have it.
+src/fsmagic.c - first set of tests the program runs, based on filesystem info
+src/funcs.c - utilility functions
+src/getline.c - replacement for OS's that don't have it.
+src/getopt_long.c - replacement for OS's that don't have it.
+src/gmtime_r.c - replacement for OS's that don't have it.
+src/is_tar.c, tar.h - knows about Tape ARchive format (courtesy John Gilmore).
+src/localtime_r.c - replacement for OS's that don't have it.
+src/magic.h.in - source file for magic.h
+src/mygetopt.h - replacement for OS's that don't have it.
+src/magic.c - the libmagic api
+src/names.h - header file for ascmagic.c
+src/pread.c - replacement for OS's that don't have it.
+src/print.c - print results, errors, warnings.
+src/readcdf.c - CDF wrapper.
+src/readelf.[ch] - Stand-alone elf parsing code.
+src/softmagic.c - 2nd set of tests, based on /etc/magic
+src/mygetopt.h - replacement for OS's that don't have it.
+src/strcasestr.c - replacement for OS's that don't have it.
+src/strlcat.c - replacement for OS's that don't have it.
+src/strlcpy.c - replacement for OS's that don't have it.
+src/tar.h - tar file definitions
+src/vasprintf.c - for systems that don't have it.
+doc/file.man - man page for the command
+doc/magic.man - man page for the magic file, courtesy Guy Harris.
+ Install as magic.4 on USG and magic.5 on V7 or Berkeley; cf Makefile.
+
+Magdir - directory of /etc/magic pieces
+------------------------------------------------------------------------------
+
+If you submit a new magic entry please make sure you read the following
+guidelines:
+
+- Initial match is preferably at least 32 bits long, and is a _unique_ match
+- If this is not feasible, use additional check
+- Match of <= 16 bits are not accepted
+- Delay printing string as much as possible, don't print output too early
+- Avoid printf arbitrary byte as string, which can be a source of
+ crash and buffer overflow
+
+- Provide complete information with entry:
+ * One line short summary
+ * Optional long description
+ * File extension, if applicable
+ * Full name and contact method (for discussion when entry has problem)
+ * Further reference, such as documentation of format
+
+------------------------------------------------------------------------------
+
+Parts of this software were developed at SoftQuad Inc., developers
+of SGML/HTML/XML publishing software, in Toronto, Canada.
+SoftQuad was swallowed up by Corel in 2002 and does not exist any longer.
diff --git a/node_modules/mmmagic/deps/libmagic/TODO b/node_modules/mmmagic/deps/libmagic/TODO
new file mode 100644
index 0000000..78890cf
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/TODO
@@ -0,0 +1,36 @@
+Most TODOs live in the TODO section of doc/file.man (i.e. file(1)).
+They are more visible there, so please add any further TODOs to that
+file, not here. More speculative material can live here.
+
+(This change was made when Reuben Thomas noticed that all the bugs
+listed in the BUGS section of the man page had been fixed!)
+
+---
+It would be nice to simplify file considerably. For example,
+reimplement the apprentice and non-pattern magic methods in Python,
+and compile the magic patterns to a giant regex (or something similar;
+maybe using Ragel (http://www.complang.org/ragel/)) so that only a
+small amount of C is needed (because fast execution is typically only
+required for soft magic, not the more detailed information given by
+hard-wired routines). In this regard, note that hplip, which is
+BSD-licensed, has a magic reimplementation in Python.
+---
+Read the kerberos magic entry for more ideas.
+---
+Write a string merger to make magic entry sizes dynamic.
+Strings will be converted to offsets from the string table.
+---
+Programming language support, we can introduce the concept of a group
+of rules where n rules need to match before the rule is positive. This
+could require structural changes to the matching code :-(
+
+0 group 2 # require 2 matches
+# rule 1
+>0 ....
+...
+# rule 2
+>0 ....
+...
+
+christos
+
diff --git a/node_modules/mmmagic/deps/libmagic/config/freebsd/config.h b/node_modules/mmmagic/deps/libmagic/config/freebsd/config.h
new file mode 100644
index 0000000..b0173f2
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/freebsd/config.h
@@ -0,0 +1,365 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#define HAVE_ASCTIME_R 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* HAVE_DAYLIGHT */
+/* #undef HAVE_DAYLIGHT */
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#define HAVE_DECL_DAYLIGHT 0
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#define HAVE_DECL_TZNAME 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dprintf' function. */
+#define HAVE_DPRINTF 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+#define HAVE_FMTCHECK 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getline' function. */
+#define HAVE_GETLINE 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+/* #undef HAVE_LIBGNURX */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #define HAVE_LIBZ 1 */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `pread' function. */
+#define HAVE_PREAD 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if the system has the type `pid_t'. */
+#define HAVE_PID_T 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_GMTOFF 1
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ISDST */
+#define HAVE_TM_ISDST 1
+
+/* HAVE_TM_ZONE */
+#define HAVE_TM_ZONE 1
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if the system has the type `int32_t'. */
+#define HAVE_INT32_T 1
+
+/* Define to 1 if the system has the type `int64_t'. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #define HAVE_ZLIB_H 1 */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+
+#ifndef HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+#ifndef HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+#ifndef HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+#ifndef HAVE_INT32_T
+typedef int int32_t;
+#endif
+#ifndef HAVE_UINT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long uint64_t;
+#else
+typedef unsigned long uint64_t;
+#endif
+#endif
+#ifndef HAVE_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef long long int64_t;
+#else
+typedef long int64_t;
+#endif
+#endif
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/node_modules/mmmagic/deps/libmagic/config/linux/config.h b/node_modules/mmmagic/deps/libmagic/config/linux/config.h
new file mode 100644
index 0000000..639c0e4
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/linux/config.h
@@ -0,0 +1,405 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#define HAVE_ASCTIME_R 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* HAVE_DAYLIGHT */
+#define HAVE_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#define HAVE_DECL_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#define HAVE_DECL_TZNAME 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dprintf' function. */
+#define HAVE_DPRINTF 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+/* #undef HAVE_FMTCHECK */
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `freelocale' function. */
+#define HAVE_FREELOCALE 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getline' function. */
+#define HAVE_GETLINE 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+/* #undef HAVE_LIBGNURX */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #define HAVE_LIBZ 1 */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#define HAVE_MKOSTEMP 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `newlocale' function. */
+#define HAVE_NEWLOCALE 1
+
+/* Define to 1 if you have the `pread' function. */
+#define HAVE_PREAD 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Have sig_t type */
+#define HAVE_SIG_T 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if the system has the type `pid_t'. */
+#define HAVE_PID_T 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_GMTOFF */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ISDST */
+#define HAVE_TM_ISDST 1
+
+/* HAVE_TM_ZONE */
+#define HAVE_TM_ZONE 1
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if the system has the type `int32_t'. */
+#define HAVE_INT32_T 1
+
+/* Define to 1 if the system has the type `int64_t'. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if the system has the type `uintptr_t'. */
+#define HAVE_UINTPTR_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `uselocale' function. */
+#define HAVE_USELOCALE 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if you have the <xlocale.h> header file. */
+#if defined(__has_include)
+# if __has_include(<xlocale.h>)
+# define HAVE_XLOCALE_H 1
+# endif
+#else
+// Assume header available for older compilers
+# define HAVE_XLOCALE_H 1
+#endif
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #define HAVE_ZLIB_H 1 */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+
+#ifndef HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+#ifndef HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+#ifndef HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+#ifndef HAVE_INT32_T
+typedef int int32_t;
+#endif
+#ifndef HAVE_UINT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long uint64_t;
+#else
+typedef unsigned long uint64_t;
+#endif
+#endif
+#ifndef HAVE_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef long long int64_t;
+#else
+typedef long int64_t;
+#endif
+#endif
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/node_modules/mmmagic/deps/libmagic/config/mac/config.h b/node_modules/mmmagic/deps/libmagic/config/mac/config.h
new file mode 100644
index 0000000..415f2a3
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/mac/config.h
@@ -0,0 +1,360 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#define HAVE_ASCTIME_R 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* HAVE_DAYLIGHT */
+#define HAVE_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#define HAVE_DECL_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#define HAVE_DECL_TZNAME 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dprintf' function. */
+#define HAVE_DPRINTF 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+#define HAVE_FMTCHECK 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getline' function. */
+/* #undef HAVE_GETLINE */
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+/* #undef HAVE_LIBGNURX */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #define HAVE_LIBZ 1 */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `pread' function. */
+#define HAVE_PREAD 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if the system has the type `pid_t'. */
+#define HAVE_PID_T 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strndup' function. */
+/* #undef HAVE_STRNDUP */
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_GMTOFF */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_ZONE */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ISDST */
+#define HAVE_TM_ISDST 1
+
+/* HAVE_TM_ZONE */
+#define HAVE_TM_ZONE 1
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if the system has the type `int32_t'. */
+#define HAVE_INT32_T 1
+
+/* Define to 1 if the system has the type `int64_t'. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #define HAVE_ZLIB_H 1 */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+
+#ifndef HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+#ifndef HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+#ifndef HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+#ifndef HAVE_INT32_T
+typedef int int32_t;
+#endif
+#ifndef HAVE_UINT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long uint64_t;
+#else
+typedef unsigned long uint64_t;
+#endif
+#endif
+#ifndef HAVE_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef long long int64_t;
+#else
+typedef long int64_t;
+#endif
+#endif
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/node_modules/mmmagic/deps/libmagic/config/openbsd/config.h b/node_modules/mmmagic/deps/libmagic/config/openbsd/config.h
new file mode 100644
index 0000000..b67c413
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/openbsd/config.h
@@ -0,0 +1,334 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#define HAVE_ASCTIME_R 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* HAVE_DAYLIGHT */
+/* #undef HAVE_DAYLIGHT */
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#define HAVE_DECL_DAYLIGHT 0
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#define HAVE_DECL_TZNAME 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dprintf' function. */
+#define HAVE_DPRINTF 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+/* #undef HAVE_FMTCHECK */
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getline' function. */
+#define HAVE_GETLINE 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+/* #undef HAVE_LIBGNURX */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #define HAVE_LIBZ 1 */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `pread' function. */
+#define HAVE_PREAD 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if the system has the type `pid_t'. */
+#define HAVE_PID_T 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_GMTOFF 1
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ISDST */
+#define HAVE_TM_ISDST 1
+
+/* HAVE_TM_ZONE */
+#define HAVE_TM_ZONE 1
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #define HAVE_ZLIB_H 1 */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/node_modules/mmmagic/deps/libmagic/config/sunos/config.h b/node_modules/mmmagic/deps/libmagic/config/sunos/config.h
new file mode 100644
index 0000000..e5e64c6
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/sunos/config.h
@@ -0,0 +1,370 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#define HAVE_ASCTIME_R 1
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the `ctime_r' function. */
+#define HAVE_CTIME_R 1
+
+/* HAVE_DAYLIGHT */
+#define HAVE_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#define HAVE_DECL_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#define HAVE_DECL_TZNAME 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dprintf' function. */
+#define HAVE_DPRINTF 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+/*#undef HAVE_FMTCHECK*/
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#define HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `getline' function. */
+#define HAVE_GETLINE 1
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getopt_long' function. */
+#define HAVE_GETOPT_LONG 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+/* #undef HAVE_LIBGNURX */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#define HAVE_MKOSTEMP 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `pread' function. */
+#define HAVE_PREAD 1
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strtof' function. */
+#define HAVE_STRTOF 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#define HAVE_STRUCT_OPTION 1
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_GMTOFF */
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_ZONE */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* HAVE_TM_ISDST */
+#define HAVE_TM_ISDST 1
+
+/* HAVE_TM_ZONE */
+/* #undef HAVE_TM_ZONE */
+
+/* HAVE_TZNAME */
+#define HAVE_TZNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define to 1 if you have the `vfork' function. */
+#define HAVE_VFORK 1
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#define HAVE_VISIBILITY 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#define HAVE_WCWIDTH 1
+
+/* Define to 1 if `fork' works. */
+#define HAVE_WORKING_FORK 1
+
+/* Define to 1 if `vfork' works. */
+#define HAVE_WORKING_VFORK 1
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #undef HAVE_ZLIB_H */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+#define MAJOR_IN_MKDEV 1
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Enable large inode numbers on Mac OS X 10.5. */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to a type if <wchar.h> does not define. */
+/* #undef mbstate_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint64_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
+
+#define HAVE_DIRENT_H 1
diff --git a/node_modules/mmmagic/deps/libmagic/config/win/config.h b/node_modules/mmmagic/deps/libmagic/config/win/config.h
new file mode 100644
index 0000000..546f560
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/config/win/config.h
@@ -0,0 +1,367 @@
+/* Define in built-in ELF support is used */
+#define BUILTIN_ELF 1
+
+/* Define for ELF core file support */
+#define ELFCORE 1
+
+/* Define to 1 if you have the `asctime_r' function. */
+#undef HAVE_ASCTIME_R
+
+/* Define to 1 if you have the `asprintf' function. */
+#undef HAVE_ASPRINTF
+
+/* Define to 1 if you have the `ctime_r' function. */
+#undef HAVE_CTIME_R
+
+/* HAVE_DAYLIGHT */
+#define HAVE_DAYLIGHT 1
+
+/* Define to 1 if you have the declaration of `daylight', and to 0 if you
+ don't. */
+#undef HAVE_DECL_DAYLIGHT
+
+/* Define to 1 if you have the declaration of `tzname', and to 0 if you don't.
+ */
+#undef HAVE_DECL_TZNAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `dprintf' function. */
+#undef HAVE_DPRINTF
+
+/* Define to 1 if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define to 1 if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fmtcheck' function. */
+/*#undef HAVE_FMTCHECK*/
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#undef HAVE_FSEEKO
+
+/* Define to 1 if you have the `getline' function. */
+#undef HAVE_GETLINE
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getopt_long' function. */
+#undef HAVE_GETOPT_LONG
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `gnurx' library (-lgnurx). */
+#undef HAVE_LIBGNURX
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if mbrtowc and mbstate_t are properly declared. */
+#define HAVE_MBRTOWC 1
+
+/* Define to 1 if <wchar.h> declares mbstate_t. */
+#define HAVE_MBSTATE_T 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#undef HAVE_MKOSTEMP
+
+/* Define to 1 if you have the `mkstemp' function. */
+#undef HAVE_MKSTEMP
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `pread' function. */
+#undef HAVE_PREAD
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define to 1 if the system has the type `pid_t'. */
+#undef HAVE_PID_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasestr' function. */
+#define HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#undef HAVE_STRLCAT
+
+/* Define to 1 if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* Define to 1 if you have the `strtof' function. */
+#undef HAVE_STRTOF
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* HAVE_STRUCT_OPTION */
+#undef HAVE_STRUCT_OPTION
+
+/* Define to 1 if `st_rdev' is a member of `struct stat'. */
+#undef HAVE_STRUCT_STAT_ST_RDEV
+
+/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_GMTOFF
+
+/* Define to 1 if `tm_zone' is a member of `struct tm'. */
+#undef HAVE_STRUCT_TM_TM_ZONE
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* HAVE_TM_ISDST */
+#undef HAVE_TM_ISDST
+
+/* HAVE_TM_ZONE */
+#undef HAVE_TM_ZONE
+
+/* HAVE_TZNAME */
+#undef HAVE_TZNAME
+
+/* Define to 1 if the system has the type `int32_t'. */
+#define HAVE_INT32_T 1
+
+/* Define to 1 if the system has the type `int64_t'. */
+#define HAVE_INT64_T 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the `utimes' function. */
+#undef HAVE_UTIMES
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the `vasprintf' function. */
+#undef HAVE_VASPRINTF
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+/* #undef HAVE_VFORK_H */
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#undef HAVE_VISIBILITY
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the `wcwidth' function. */
+#undef HAVE_WCWIDTH
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #undef HAVE_ZLIB_H */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+#undef MAJOR_IN_MKDEV
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+#undef MAJOR_IN_SYSMACROS
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+#undef _LARGEFILE_SOURCE
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to empty if `const' does not conform to ANSI C. */
+//#define const
+
+/* Define to a type if <wchar.h> does not define. */
+//#undef mbstate_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+//#undef off_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+//#undef size_t
+
+
+#ifndef HAVE_UINT8_T
+typedef unsigned char uint8_t;
+#endif
+#ifndef HAVE_UINT16_T
+typedef unsigned short uint16_t;
+#endif
+#ifndef HAVE_UINT32_T
+typedef unsigned int uint32_t;
+#endif
+#ifndef HAVE_INT32_T
+typedef int int32_t;
+#endif
+#ifndef HAVE_UINT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long uint64_t;
+#else
+typedef unsigned long uint64_t;
+#endif
+#endif
+#ifndef HAVE_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef long long int64_t;
+#else
+typedef long int64_t;
+#endif
+#endif
+
+#include <crtdefs.h>
+
+/* Define as `fork' if `vfork' does not work. */
+/* #undef vfork */
diff --git a/node_modules/mmmagic/deps/libmagic/libmagic.gyp b/node_modules/mmmagic/deps/libmagic/libmagic.gyp
new file mode 100644
index 0000000..76be697
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/libmagic.gyp
@@ -0,0 +1,85 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'libmagic',
+ 'type': 'static_library',
+ 'include_dirs': [ '.', 'src' ],
+ 'defines': [ 'HAVE_CONFIG_H', 'VERSION="5.32"' ],
+ 'conditions': [
+ [ 'OS!="freebsd" and OS!="mac"', {
+ 'sources': [ 'src/fmtcheck.c' ],
+ }],
+ [ 'OS=="win"', {
+ 'sources': [
+ 'src/asctime_r.c',
+ 'src/asprintf.c',
+ 'src/ctime_r.c',
+ 'src/dprintf.c',
+ 'src/getline.c',
+ 'src/gmtime_r.c',
+ 'src/localtime_r.c',
+ 'src/pread.c',
+ 'src/snprintf.c',
+ 'src/strcasestr.c',
+ 'src/strlcat.c',
+ 'src/strlcpy.c',
+ 'src/vasprintf.c',
+ # POSIX regex implementation
+ 'msvc/libgnurx-2.5/regex.c',
+ ],
+ 'include_dirs': [ 'config/win', 'msvc', 'msvc/libgnurx-2.5' ],
+ 'link_settings': {
+ 'libraries': [
+ '-lshlwapi.lib',
+ ]
+ },
+ }, { # POSIX
+ 'cflags': [ '-std=c99' ],
+ }],
+ [ 'OS=="linux"', {
+ 'sources': [
+ 'src/strlcat.c',
+ 'src/strlcpy.c',
+ ],
+ 'include_dirs': [ 'config/linux' ],
+ }],
+ [ 'OS=="mac"', {
+ 'include_dirs': [ 'config/mac' ],
+ }],
+ [ 'OS=="freebsd"', {
+ 'include_dirs': [ 'config/freebsd' ],
+ }],
+ [ 'OS=="openbsd"', {
+ 'include_dirs': [ 'config/openbsd' ],
+ }],
+ [ 'OS=="solaris"', {
+ 'include_dirs': [ 'config/sunos' ],
+ }],
+ ],
+ 'cflags!': [ '-O2' ],
+ 'cflags+': [ '-O3' ],
+ 'cflags_cc!': [ '-O2' ],
+ 'cflags_cc+': [ '-O3' ],
+ 'cflags_c!': [ '-O2' ],
+ 'cflags_c+': [ '-O3' ],
+ 'sources': [
+ 'src/apprentice.c',
+ 'src/apptype.c',
+ 'src/ascmagic.c',
+ 'src/cdf.c',
+ 'src/cdf_time.c',
+ 'src/compress.c',
+ 'src/der.c',
+ 'src/encoding.c',
+ 'src/fsmagic.c',
+ 'src/funcs.c',
+ 'src/is_tar.c',
+ 'src/magic.c',
+ 'src/print.c',
+ 'src/readcdf.c',
+ 'src/readelf.c',
+ 'src/softmagic.c',
+ ],
+ },
+ ]
+}
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/dirent.h b/node_modules/mmmagic/deps/libmagic/msvc/dirent.h
new file mode 100644
index 0000000..445d040
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/dirent.h
@@ -0,0 +1,372 @@
+/*****************************************************************************
+ * dirent.h - dirent API for Microsoft Visual Studio
+ *
+ * Copyright (C) 2006 Toni Ronkko
+ *
+ * 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 TONI RONKKO 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.
+ *
+ * Mar 15, 2011, Toni Ronkko
+ * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Added d_type and d_namlen fields to dirent structure. The former is
+ * especially useful for determining whether directory entry represents a
+ * file or a directory. For more information, see
+ * http://www.delorie.com/gnu/docs/glibc/libc_270.html
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Improved conformance to the standards. For example, errno is now set
+ * properly on failure and assert() is never used. Thanks to Peter Brockam
+ * for suggestions.
+ *
+ * Aug 11, 2010, Toni Ronkko
+ * Fixed a bug in rewinddir(): when using relative directory names, change
+ * of working directory no longer causes rewinddir() to fail.
+ *
+ * Dec 15, 2009, John Cunningham
+ * Added rewinddir member function
+ *
+ * Jan 18, 2008, Toni Ronkko
+ * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
+ * between multi-byte and unicode representations. This makes the
+ * code simpler and also allows the code to be compiled under MingW. Thanks
+ * to Azriel Fasten for the suggestion.
+ *
+ * Mar 4, 2007, Toni Ronkko
+ * Bug fix: due to the strncpy_s() function this file only compiled in
+ * Visual Studio 2005. Using the new string functions only when the
+ * compiler version allows.
+ *
+ * Nov 2, 2006, Toni Ronkko
+ * Major update: removed support for Watcom C, MS-DOS and Turbo C to
+ * simplify the file, updated the code to compile cleanly on Visual
+ * Studio 2005 with both unicode and multi-byte character strings,
+ * removed rewinddir() as it had a bug.
+ *
+ * Aug 20, 2006, Toni Ronkko
+ * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified
+ * comments by removing SGML tags.
+ *
+ * May 14 2002, Toni Ronkko
+ * Embedded the function definitions directly to the header so that no
+ * source modules need to be included in the Visual Studio project. Removed
+ * all the dependencies to other projects so that this very header can be
+ * used independently.
+ *
+ * May 28 1998, Toni Ronkko
+ * First version.
+ *****************************************************************************/
+#ifndef DIRENT_H
+#define DIRENT_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+/* Entries missing from MSVC 6.0 */
+#if !defined(FILE_ATTRIBUTE_DEVICE)
+# define FILE_ATTRIBUTE_DEVICE 0x40
+#endif
+
+/* File type and permission flags for stat() */
+#if defined(_MSC_VER) && !defined(S_IREAD)
+# define S_IFMT _S_IFMT /* file type mask */
+# define S_IFDIR _S_IFDIR /* directory */
+# define S_IFCHR _S_IFCHR /* character device */
+# define S_IFFIFO _S_IFFIFO /* pipe */
+# define S_IFREG _S_IFREG /* regular file */
+# define S_IREAD _S_IREAD /* read permission */
+# define S_IWRITE _S_IWRITE /* write permission */
+# define S_IEXEC _S_IEXEC /* execute permission */
+#endif
+#define S_IFBLK 0 /* block device */
+#define S_IFLNK 0 /* link */
+#define S_IFSOCK 0 /* socket */
+
+#if defined(_MSC_VER)
+# define S_IRUSR S_IREAD /* read, user */
+# define S_IWUSR S_IWRITE /* write, user */
+# define S_IXUSR 0 /* execute, user */
+# define S_IRGRP 0 /* read, group */
+# define S_IWGRP 0 /* write, group */
+# define S_IXGRP 0 /* execute, group */
+# define S_IROTH 0 /* read, others */
+# define S_IWOTH 0 /* write, others */
+# define S_IXOTH 0 /* execute, others */
+#endif
+
+/* Indicates that d_type field is available in dirent structure */
+#define _DIRENT_HAVE_D_TYPE
+
+/* File type flags for d_type */
+#define DT_UNKNOWN 0
+#define DT_REG S_IFREG
+#define DT_DIR S_IFDIR
+#define DT_FIFO S_IFFIFO
+#define DT_SOCK S_IFSOCK
+#define DT_CHR S_IFCHR
+#define DT_BLK S_IFBLK
+
+/* Macros for converting between st_mode and d_type */
+#define IFTODT(mode) ((mode) & S_IFMT)
+#define DTTOIF(type) (type)
+
+/*
+ * File type macros. Note that block devices, sockets and links cannot be
+ * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
+ * only defined for compatibility. These macros should always return false
+ * on Windows.
+ */
+#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
+#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct dirent
+{
+ char d_name[MAX_PATH + 1]; /* File name */
+ size_t d_namlen; /* Length of name without \0 */
+ int d_type; /* File type */
+} dirent;
+
+
+typedef struct DIR
+{
+ dirent curentry; /* Current directory entry */
+ WIN32_FIND_DATAA find_data; /* Private file data */
+ int cached; /* True if data is valid */
+ HANDLE search_handle; /* Win32 search handle */
+ char patt[MAX_PATH + 3]; /* Initial directory name */
+} DIR;
+
+
+/* Forward declarations */
+static DIR *opendir(const char *dirname);
+static struct dirent *readdir(DIR *dirp);
+static int closedir(DIR *dirp);
+static void rewinddir(DIR* dirp);
+
+
+/* Use the new safe string functions introduced in Visual Studio 2005 */
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
+#else
+# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
+#endif
+
+/* Set errno variable */
+#if defined(_MSC_VER)
+#define DIRENT_SET_ERRNO(x) _set_errno (x)
+#else
+#define DIRENT_SET_ERRNO(x) (errno = (x))
+#endif
+
+
+/*****************************************************************************
+ * Open directory stream DIRNAME for read and return a pointer to the
+ * internal working area that is used to retrieve individual directory
+ * entries.
+ */
+static DIR *opendir(const char *dirname)
+{
+ DIR *dirp;
+
+ /* ensure that the resulting search pattern will be a valid file name */
+ if (dirname == NULL) {
+ DIRENT_SET_ERRNO (ENOENT);
+ return NULL;
+ }
+ if (strlen (dirname) + 3 >= MAX_PATH) {
+ DIRENT_SET_ERRNO (ENAMETOOLONG);
+ return NULL;
+ }
+
+ /* construct new DIR structure */
+ dirp = (DIR*) malloc (sizeof (struct DIR));
+ if (dirp != NULL) {
+ int error;
+
+ /*
+ * Convert relative directory name to an absolute one. This
+ * allows rewinddir() to function correctly when the current working
+ * directory is changed between opendir() and rewinddir().
+ */
+ if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
+ char *p;
+
+ /* append the search pattern "\\*\0" to the directory name */
+ p = strchr (dirp->patt, '\0');
+ if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
+ *p++ = '\\';
+ }
+ *p++ = '*';
+ *p = '\0';
+
+ /* open directory stream and retrieve the first entry */
+ dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ /* a directory entry is now waiting in memory */
+ dirp->cached = 1;
+ error = 0;
+ } else {
+ /* search pattern is not a directory name? */
+ DIRENT_SET_ERRNO (ENOENT);
+ error = 1;
+ }
+ } else {
+ /* buffer too small */
+ DIRENT_SET_ERRNO (ENOMEM);
+ error = 1;
+ }
+
+ if (error) {
+ free (dirp);
+ dirp = NULL;
+ }
+ }
+
+ return dirp;
+}
+
+
+/*****************************************************************************
+ * Read a directory entry, and return a pointer to a dirent structure
+ * containing the name of the entry in d_name field. Individual directory
+ * entries returned by this very function include regular files,
+ * sub-directories, pseudo-directories "." and "..", but also volume labels,
+ * hidden files and system files may be returned.
+ */
+static struct dirent *readdir(DIR *dirp)
+{
+ DWORD attr;
+ if (dirp == NULL) {
+ /* directory stream did not open */
+ DIRENT_SET_ERRNO (EBADF);
+ return NULL;
+ }
+
+ /* get next directory entry */
+ if (dirp->cached != 0) {
+ /* a valid directory entry already in memory */
+ dirp->cached = 0;
+ } else {
+ /* get the next directory entry from stream */
+ if (dirp->search_handle == INVALID_HANDLE_VALUE) {
+ return NULL;
+ }
+ if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
+ /* the very last entry has been processed or an error occured */
+ FindClose (dirp->search_handle);
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+ }
+
+ /* copy as a multibyte character string */
+ DIRENT_STRNCPY ( dirp->curentry.d_name,
+ dirp->find_data.cFileName,
+ sizeof(dirp->curentry.d_name) );
+ dirp->curentry.d_name[MAX_PATH] = '\0';
+
+ /* compute the length of name */
+ dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
+
+ /* determine file type */
+ attr = dirp->find_data.dwFileAttributes;
+ if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
+ dirp->curentry.d_type = DT_CHR;
+ } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+ dirp->curentry.d_type = DT_DIR;
+ } else {
+ dirp->curentry.d_type = DT_REG;
+ }
+ return &dirp->curentry;
+}
+
+
+/*****************************************************************************
+ * Close directory stream opened by opendir() function. Close of the
+ * directory stream invalidates the DIR structure as well as any previously
+ * read directory entry.
+ */
+static int closedir(DIR *dirp)
+{
+ if (dirp == NULL) {
+ /* invalid directory stream */
+ DIRENT_SET_ERRNO (EBADF);
+ return -1;
+ }
+
+ /* release search handle */
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ FindClose (dirp->search_handle);
+ dirp->search_handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* release directory structure */
+ free (dirp);
+ return 0;
+}
+
+
+/*****************************************************************************
+ * Resets the position of the directory stream to which dirp refers to the
+ * beginning of the directory. It also causes the directory stream to refer
+ * to the current state of the corresponding directory, as a call to opendir()
+ * would have done. If dirp does not refer to a directory stream, the effect
+ * is undefined.
+ */
+static void rewinddir(DIR* dirp)
+{
+ if (dirp != NULL) {
+ /* release search handle */
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ FindClose (dirp->search_handle);
+ }
+
+ /* open new search handle and retrieve the first entry */
+ dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
+ if (dirp->search_handle != INVALID_HANDLE_VALUE) {
+ /* a directory entry is now waiting in memory */
+ dirp->cached = 1;
+ } else {
+ /* failed to re-open directory: no directory entry in memory */
+ dirp->cached = 0;
+ }
+ }
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*DIRENT_H*/
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/inttypes.h b/node_modules/mmmagic/deps/libmagic/msvc/inttypes.h
new file mode 100644
index 0000000..4b3828a
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/inttypes.h
@@ -0,0 +1,305 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/COPYING.LIB b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/COPYING.LIB
new file mode 100644
index 0000000..cf9b6b9
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/COPYING.LIB
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+^L
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+^L
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+^L
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+^L
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+^L
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+^L
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+^L
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+^L
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/Makefile b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/Makefile
new file mode 100644
index 0000000..f777eea
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/Makefile
@@ -0,0 +1,41 @@
+all: libgnurx-0.dll libgnurx.dll.a libregex.a
+
+THIS = libgnurx
+VERSION = 2.5
+
+CC = x86_64-w64-mingw32-gcc -mthreads
+CFLAGS = -I .
+
+SOURCES = $(wildcard *.c *.h)
+OBJECTS = regex.o
+
+libgnurx-0.dll libgnurx.dll.a: $(OBJECTS) Makefile
+ $(CC) -shared -o libgnurx-0.dll -Wl,--enable-auto-image-base -Wl,--out-implib,libgnurx.dll.a -Wl,--output-def,libgnurx.def $(OBJECTS)
+
+libregex.a: libgnurx.dll.a
+ cp -p libgnurx.dll.a $@
+
+dist: $(THIS)-$(VERSION).zip $(THIS)-dev-$(VERSION).zip $(THIS)-src-$(VERSION).zip
+
+$(THIS)-$(VERSION).zip: libgnurx-0.dll
+ mkdir -p runtime/bin
+ cp -p libgnurx-0.dll runtime/bin
+ (cd runtime; zip -r ../$(THIS)-$(VERSION).zip bin)
+ rm -rf runtime
+
+$(THIS)-dev-$(VERSION).zip: regex.h libgnurx.dll.a libregex.a
+ mkdir -p dev/include dev/lib
+ cp -p regex.h dev/include
+ cp -p libgnurx.dll.a libregex.a gnurx.lib dev/lib
+ (cd dev; zip -r ../$(THIS)-dev-$(VERSION).zip .)
+ rm -rf dev
+
+$(THIS)-src-$(VERSION).zip: Makefile README COPYING.LIB $(SOURCES)
+ mkdir $(THIS)-$(VERSION)
+ cp -p Makefile README COPYING.LIB $(SOURCES) $(THIS)-$(VERSION)
+ zip -r $@ $(THIS)-$(VERSION$)
+ rm -rf $(THIS)-$(VERSION$)
+
+clean:
+ rm -f *~ *.o *.dll *.def *.exp *.a *.zip
+ rm -rf runtime dev $(THIS)-$(VERSION)
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README
new file mode 100644
index 0000000..534cc3c
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README
@@ -0,0 +1,33 @@
+This is the regex functionality from glibc 2.5 extracted into a
+separate library, for Win32.
+
+I call the DLL libgnurx-0.dll which hopefully should be unique. At
+least it isn't "regex.dll" which has been used by the
+gnuwin32.sourceforge.net site for *two* incompatible DLLs. (That mess,
+and the mess with their build of Henry Spencer's regex library, was
+what lead me to build my own GNU regex library. See the gnuwin32-users mailing list archives from December 2006.)
+
+The "-0" is so that if at some point I build a release that isn't
+binary compatible, I can then increment that and use a different name.
+
+The import library for gcc is called libgnurx.dll.a, but I also
+distribute a copy of it called libregex.a so that configure scripts
+that look for -lregex will work.
+
+Note that none of the wide-character and i18n functionality which is
+built when this is part of glibc gets compiled. Thus things like
+character classes most probably work only for single-byte codepages.
+
+Compiling that stuff would drag in lots of glibc's locale handling
+stuff which is completely incompatible with Microsoft's C library's
+locale handling anyway. Also, I am not sure whether the GNU regex code
+is prepared to handle a two-byte wchar_t, or does it assume that
+wchar_t is int as it is on Linux? Hmm, actually there is lots of
+sizeof(wchar_t) in glibc, so maybe it *is* prepared? Maybe
+later... But anyway, it would presumably mean we should have not just
+the regex functionality but a larger subset of glibc that would
+include all locale, ctype, wchar, mbs, etc stuff, presumably ending up
+with a very large part of glibc (not the system calls,
+obviously). Indeed, something to save for later, or never...
+
+--Tor Lillqvist <tml@iki.fi>, <tml@novell.com>
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README.md b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README.md
new file mode 100644
index 0000000..6e761b1
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/README.md
@@ -0,0 +1,10 @@
+This version of libgnurx was taken from https://github.com/nscaife/file-windows/tree/master/libgnurx-2.5.
+
+Only one modification has been made to the code taken from the above source: regexec.c contained a ternary expression with a missing expression, which is not supported by the Visual C compiler, so the missing expression has been re-added.
+
+Original README.md below
+========================
+
+The contents of this directory are from http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/.
+
+I have made a few modifications to the Makefile to disable creation of gnurx.lib. The creation of this file relies on lib.exe from Visual Studio (forcing a Windows build environment), and is not needed to build libmagic or file.
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regcomp.c b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regcomp.c
new file mode 100644
index 0000000..78a1218
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regcomp.c
@@ -0,0 +1,3800 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002,2003,2004,2005,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+ size_t length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+ const re_dfastate_t *init_state,
+ char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif /* RE_ENABLE_I18N */
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t preorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+ reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+ bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
+static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+ int node, int root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static int fetch_number (re_string_t *input, re_token_t *token,
+ reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+ reg_syntax_t syntax) internal_function;
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+ re_token_t *token, reg_syntax_t syntax,
+ int nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+ re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax,
+ reg_errcode_t *err);
+static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token, int token_len,
+ re_dfa_t *dfa,
+ reg_syntax_t syntax,
+ int accept_hyphen);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+ re_string_t *regexp,
+ re_token_t *token);
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *equiv_class_alloc,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ re_charset_t *mbcset,
+ int *char_class_alloc,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#else /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+ const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+ bitset_t sbcset,
+ const unsigned char *class_name,
+ reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+ RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra,
+ int non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+ bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+const char __re_error_msgid[] attribute_hidden =
+ {
+#define REG_NOERROR_IDX 0
+ gettext_noop ("Success") /* REG_NOERROR */
+ "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+ gettext_noop ("No match") /* REG_NOMATCH */
+ "\0"
+#define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match")
+ gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+ "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+ gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+ "\0"
+#define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character")
+ gettext_noop ("Invalid character class name") /* REG_ECTYPE */
+ "\0"
+#define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name")
+ gettext_noop ("Trailing backslash") /* REG_EESCAPE */
+ "\0"
+#define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash")
+ gettext_noop ("Invalid back reference") /* REG_ESUBREG */
+ "\0"
+#define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference")
+ gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */
+ "\0"
+#define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^")
+ gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */
+ "\0"
+#define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(")
+ gettext_noop ("Unmatched \\{") /* REG_EBRACE */
+ "\0"
+#define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{")
+ gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */
+ "\0"
+#define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}")
+ gettext_noop ("Invalid range end") /* REG_ERANGE */
+ "\0"
+#define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end")
+ gettext_noop ("Memory exhausted") /* REG_ESPACE */
+ "\0"
+#define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted")
+ gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */
+ "\0"
+#define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression")
+ gettext_noop ("Premature end of regular expression") /* REG_EEND */
+ "\0"
+#define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression")
+ gettext_noop ("Regular expression too big") /* REG_ESIZE */
+ "\0"
+#define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big")
+ gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */
+ };
+
+const size_t __re_error_msgid_idx[] attribute_hidden =
+ {
+ REG_NOERROR_IDX,
+ REG_NOMATCH_IDX,
+ REG_BADPAT_IDX,
+ REG_ECOLLATE_IDX,
+ REG_ECTYPE_IDX,
+ REG_EESCAPE_IDX,
+ REG_ESUBREG_IDX,
+ REG_EBRACK_IDX,
+ REG_EPAREN_IDX,
+ REG_EBRACE_IDX,
+ REG_BADBR_IDX,
+ REG_ERANGE_IDX,
+ REG_ESPACE_IDX,
+ REG_BADRPT_IDX,
+ REG_EEND_IDX,
+ REG_ESIZE_IDX,
+ REG_ERPAREN_IDX
+ };
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length LENGTH) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ size_t length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub, unless RE_NO_SUB is set. */
+ bufp->no_sub = !!(re_syntax_options & RE_NO_SUB);
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = re_compile_internal (bufp, pattern, length, re_syntax_options);
+
+ if (!ret)
+ return NULL;
+ return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+#ifdef _LIBC
+weak_alias (__re_compile_pattern, re_compile_pattern)
+#endif
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+#ifdef _LIBC
+weak_alias (__re_set_syntax, re_set_syntax)
+#endif
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ char *fastmap = bufp->fastmap;
+
+ memset (fastmap, '\0', sizeof (char) * SBC_MAX);
+ re_compile_fastmap_iter (bufp, dfa->init_state, fastmap);
+ if (dfa->init_state != dfa->init_state_word)
+ re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap);
+ if (dfa->init_state != dfa->init_state_nl)
+ re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap);
+ if (dfa->init_state != dfa->init_state_begbuf)
+ re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap);
+ bufp->fastmap_accurate = 1;
+ return 0;
+}
+#ifdef _LIBC
+weak_alias (__re_compile_fastmap, re_compile_fastmap)
+#endif
+
+static inline void
+__attribute ((always_inline))
+re_set_fastmap (char *fastmap, int icase, int ch)
+{
+ fastmap[ch] = 1;
+ if (icase)
+ fastmap[tolower (ch)] = 1;
+}
+
+/* Helper function for re_compile_fastmap.
+ Compile fastmap for the initial_state INIT_STATE. */
+
+static void
+re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state,
+ char *fastmap)
+{
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+ int node_cnt;
+ int icase = (dfa->mb_cur_max == 1 && (bufp->syntax & RE_ICASE));
+ for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt)
+ {
+ int node = init_state->nodes.elems[node_cnt];
+ re_token_type_t type = dfa->nodes[node].type;
+
+ if (type == CHARACTER)
+ {
+ re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c);
+#ifdef RE_ENABLE_I18N
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ unsigned char *buf = alloca (dfa->mb_cur_max), *p;
+ wchar_t wc;
+ mbstate_t state;
+
+ p = buf;
+ *p++ = dfa->nodes[node].opr.c;
+ while (++node < dfa->nodes_len
+ && dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].mb_partial)
+ *p++ = dfa->nodes[node].opr.c;
+ memset (&state, '\0', sizeof (state));
+ if (mbrtowc (&wc, (const char *) buf, p - buf,
+ &state) == p - buf
+ && (__wcrtomb ((char *) buf, towlower (wc), &state)
+ != (size_t) -1))
+ re_set_fastmap (fastmap, 0, buf[0]);
+ }
+#endif
+ }
+ else if (type == SIMPLE_BRACKET)
+ {
+ int i, ch;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ {
+ int j;
+ bitset_word_t w = dfa->nodes[node].opr.sbcset[i];
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (w & ((bitset_word_t) 1 << j))
+ re_set_fastmap (fastmap, icase, ch);
+ }
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == COMPLEX_BRACKET)
+ {
+ int i;
+ re_charset_t *cset = dfa->nodes[node].opr.mbcset;
+ if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes
+ || cset->nranges || cset->nchar_classes)
+ {
+# ifdef _LIBC
+ if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0)
+ {
+ /* In this case we want to catch the bytes which are
+ the first byte of any collation elements.
+ e.g. In da_DK, we want to catch 'a' since "aa"
+ is a valid collation element, and don't catch
+ 'b' since 'b' is the only collation element
+ which starts from 'b'. */
+ const int32_t *table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ for (i = 0; i < SBC_MAX; ++i)
+ if (table[i] < 0)
+ re_set_fastmap (fastmap, icase, i);
+ }
+# else
+ if (dfa->mb_cur_max > 1)
+ for (i = 0; i < SBC_MAX; ++i)
+ if (__btowc (i) == WEOF)
+ re_set_fastmap (fastmap, icase, i);
+# endif /* not _LIBC */
+ }
+ for (i = 0; i < cset->nmbchars; ++i)
+ {
+ char buf[256];
+ mbstate_t state;
+ memset (&state, '\0', sizeof (state));
+ if (__wcrtomb (buf, cset->mbchars[i], &state) != (size_t) -1)
+ re_set_fastmap (fastmap, icase, *(unsigned char *) buf);
+ if ((bufp->syntax & RE_ICASE) && dfa->mb_cur_max > 1)
+ {
+ if (__wcrtomb (buf, towlower (cset->mbchars[i]), &state)
+ != (size_t) -1)
+ re_set_fastmap (fastmap, 0, *(unsigned char *) buf);
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ else if (type == OP_PERIOD
+#ifdef RE_ENABLE_I18N
+ || type == OP_UTF8_PERIOD
+#endif /* RE_ENABLE_I18N */
+ || type == END_OF_RE)
+ {
+ memset (fastmap, '\1', sizeof (char) * SBC_MAX);
+ if (type == END_OF_RE)
+ bufp->can_be_null = 1;
+ return;
+ }
+ }
+}
+
+/* Entry point for POSIX code. */
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' to an allocated space for the fastmap;
+ `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (preg, pattern, cflags)
+ regex_t *__restrict preg;
+ const char *__restrict pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED
+ : RE_SYNTAX_POSIX_BASIC);
+
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Try to allocate space for the fastmap. */
+ preg->fastmap = re_malloc (char, SBC_MAX);
+ if (BE (preg->fastmap == NULL, 0))
+ return REG_ESPACE;
+
+ syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+ preg->no_sub = !!(cflags & REG_NOSUB);
+ preg->translate = NULL;
+
+ ret = re_compile_internal (preg, pattern, strlen (pattern), syntax);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN)
+ ret = REG_EPAREN;
+
+ /* We have already checked preg->fastmap != NULL. */
+ if (BE (ret == REG_NOERROR, 1))
+ /* Compute the fastmap now, since regexec cannot modify the pattern
+ buffer. This function never fails in this implementation. */
+ (void) re_compile_fastmap (preg);
+ else
+ {
+ /* Some error occurred while compiling the expression. */
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+ }
+
+ return (int) ret;
+}
+#ifdef _LIBC
+weak_alias (__regcomp, regcomp)
+#endif
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *__restrict preg;
+ char *__restrict errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (BE (errcode < 0
+ || errcode >= (int) (sizeof (__re_error_msgid_idx)
+ / sizeof (__re_error_msgid_idx[0])), 0))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (BE (errbuf_size != 0, 1))
+ {
+ if (BE (msg_size > errbuf_size, 0))
+ {
+#if defined HAVE_MEMPCPY || defined _LIBC
+ *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0';
+#else
+ memcpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+#endif
+ }
+ else
+ memcpy (errbuf, msg, msg_size);
+ }
+
+ return msg_size;
+}
+#ifdef _LIBC
+weak_alias (__regerror, regerror)
+#endif
+
+
+#ifdef RE_ENABLE_I18N
+/* This static array is used for the map to single-byte characters when
+ UTF-8 is used. Otherwise we would allocate memory just to initialize
+ it the same all the time. UTF-8 is the preferred encoding so this is
+ a worthwhile optimization. */
+static const bitset_t utf8_sb_map =
+{
+ /* Set the first 128 bits. */
+ [0 ... 0x80 / BITSET_WORD_BITS - 1] = BITSET_WORD_MAX
+};
+#endif
+
+
+static void
+free_dfa_content (re_dfa_t *dfa)
+{
+ int i, j;
+
+ if (dfa->nodes)
+ for (i = 0; i < dfa->nodes_len; ++i)
+ free_token (dfa->nodes + i);
+ re_free (dfa->nexts);
+ for (i = 0; i < dfa->nodes_len; ++i)
+ {
+ if (dfa->eclosures != NULL)
+ re_node_set_free (dfa->eclosures + i);
+ if (dfa->inveclosures != NULL)
+ re_node_set_free (dfa->inveclosures + i);
+ if (dfa->edests != NULL)
+ re_node_set_free (dfa->edests + i);
+ }
+ re_free (dfa->edests);
+ re_free (dfa->eclosures);
+ re_free (dfa->inveclosures);
+ re_free (dfa->nodes);
+
+ if (dfa->state_table)
+ for (i = 0; i <= dfa->state_hash_mask; ++i)
+ {
+ struct re_state_table_entry *entry = dfa->state_table + i;
+ for (j = 0; j < entry->num; ++j)
+ {
+ re_dfastate_t *state = entry->array[j];
+ free_state (state);
+ }
+ re_free (entry->array);
+ }
+ re_free (dfa->state_table);
+#ifdef RE_ENABLE_I18N
+ if (dfa->sb_char != utf8_sb_map)
+ re_free (dfa->sb_char);
+#endif
+ re_free (dfa->subexp_map);
+#ifdef DEBUG
+ re_free (dfa->re_str);
+#endif
+
+ re_free (dfa);
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ if (BE (dfa != NULL, 1))
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+
+ re_free (preg->fastmap);
+ preg->fastmap = NULL;
+
+ re_free (preg->translate);
+ preg->translate = NULL;
+}
+#ifdef _LIBC
+weak_alias (__regfree, regfree)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+# ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec above without link errors. */
+weak_function
+# endif
+re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+ char *fastmap;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (re_comp_buf.buffer)
+ {
+ fastmap = re_comp_buf.fastmap;
+ re_comp_buf.fastmap = NULL;
+ __regfree (&re_comp_buf);
+ memset (&re_comp_buf, '\0', sizeof (re_comp_buf));
+ re_comp_buf.fastmap = fastmap;
+ }
+
+ if (re_comp_buf.fastmap == NULL)
+ {
+ re_comp_buf.fastmap = (char *) malloc (SBC_MAX);
+ if (re_comp_buf.fastmap == NULL)
+ return (char *) gettext (__re_error_msgid
+ + __re_error_msgid_idx[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]);
+}
+
+#ifdef _LIBC
+libc_freeres_fn (free_mem)
+{
+ __regfree (&re_comp_buf);
+}
+#endif
+
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point.
+ Compile the regular expression PATTERN, whose length is LENGTH.
+ SYNTAX indicate regular expression's syntax. */
+
+static reg_errcode_t
+re_compile_internal (regex_t *preg, const char * pattern, size_t length,
+ reg_syntax_t syntax)
+{
+ reg_errcode_t err = REG_NOERROR;
+ re_dfa_t *dfa;
+ re_string_t regexp;
+
+ /* Initialize the pattern buffer. */
+ preg->fastmap_accurate = 0;
+ preg->syntax = syntax;
+ preg->not_bol = preg->not_eol = 0;
+ preg->used = 0;
+ preg->re_nsub = 0;
+ preg->can_be_null = 0;
+ preg->regs_allocated = REGS_UNALLOCATED;
+
+ /* Initialize the dfa. */
+ dfa = (re_dfa_t *) preg->buffer;
+ if (BE (preg->allocated < sizeof (re_dfa_t), 0))
+ {
+ /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. If ->buffer is NULL this
+ is a simple allocation. */
+ dfa = re_realloc (preg->buffer, re_dfa_t, 1);
+ if (dfa == NULL)
+ return REG_ESPACE;
+ preg->allocated = sizeof (re_dfa_t);
+ preg->buffer = (unsigned char *) dfa;
+ }
+ preg->used = sizeof (re_dfa_t);
+
+ err = init_dfa (dfa, length);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+#ifdef DEBUG
+ /* Note: length+1 will not overflow since it is checked in init_dfa. */
+ dfa->re_str = re_malloc (char, length + 1);
+ strncpy (dfa->re_str, pattern, length + 1);
+#endif
+
+ __libc_lock_init (dfa->lock);
+
+ err = re_string_construct (&regexp, pattern, length, preg->translate,
+ syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_compile_internal_free_return:
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ return err;
+ }
+
+ /* Parse the regular expression, and build a structure tree. */
+ preg->re_nsub = 0;
+ dfa->str_tree = parse (&regexp, preg, syntax, &err);
+ if (BE (dfa->str_tree == NULL, 0))
+ goto re_compile_internal_free_return;
+
+ /* Analyze the tree and create the nfa. */
+ err = analyze (preg);
+ if (BE (err != REG_NOERROR, 0))
+ goto re_compile_internal_free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* If possible, do searching in single byte encoding to speed things up. */
+ if (dfa->is_utf8 && !(syntax & RE_ICASE) && preg->translate == NULL)
+ optimize_utf8 (dfa);
+#endif
+
+ /* Then create the initial state of the dfa. */
+ err = create_initial_state (dfa);
+
+ /* Release work areas. */
+ free_workarea_compile (preg);
+ re_string_destruct (&regexp);
+
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_dfa_content (dfa);
+ preg->buffer = NULL;
+ preg->allocated = 0;
+ }
+
+ return err;
+}
+
+/* Initialize DFA. We use the length of the regular expression PAT_LEN
+ as the initial length of some arrays. */
+
+static reg_errcode_t
+init_dfa (re_dfa_t *dfa, size_t pat_len)
+{
+ unsigned int table_size;
+#ifndef _LIBC
+ char *codeset_name;
+#endif
+
+ memset (dfa, '\0', sizeof (re_dfa_t));
+
+ /* Force allocation of str_tree_storage the first time. */
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+
+ /* Avoid overflows. */
+ if (pat_len == SIZE_MAX)
+ return REG_ESPACE;
+
+ dfa->nodes_alloc = pat_len + 1;
+ dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc);
+
+ /* table_size = 2 ^ ceil(log pat_len) */
+ for (table_size = 1; ; table_size <<= 1)
+ if (table_size > pat_len)
+ break;
+
+ dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size);
+ dfa->state_hash_mask = table_size - 1;
+
+ dfa->mb_cur_max = MB_CUR_MAX;
+#ifdef _LIBC
+ if (dfa->mb_cur_max == 6
+ && strcmp (_NL_CURRENT (LC_CTYPE, _NL_CTYPE_CODESET_NAME), "UTF-8") == 0)
+ dfa->is_utf8 = 1;
+ dfa->map_notascii = (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MAP_TO_NONASCII)
+ != 0);
+#else
+# ifdef HAVE_LANGINFO_CODESET
+ codeset_name = nl_langinfo (CODESET);
+# else
+ codeset_name = getenv ("LC_ALL");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LC_CTYPE");
+ if (codeset_name == NULL || codeset_name[0] == '\0')
+ codeset_name = getenv ("LANG");
+ if (codeset_name == NULL)
+ codeset_name = "";
+ else if (strchr (codeset_name, '.') != NULL)
+ codeset_name = strchr (codeset_name, '.') + 1;
+# endif
+
+ if (strcasecmp (codeset_name, "UTF-8") == 0
+ || strcasecmp (codeset_name, "UTF8") == 0)
+ dfa->is_utf8 = 1;
+
+ /* We check exhaustively in the loop below if this charset is a
+ superset of ASCII. */
+ dfa->map_notascii = 0;
+#endif
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ if (dfa->is_utf8)
+ dfa->sb_char = (re_bitset_ptr_t) utf8_sb_map;
+ else
+ {
+ int i, j, ch;
+
+ dfa->sb_char = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+ if (BE (dfa->sb_char == NULL, 0))
+ return REG_ESPACE;
+
+ /* Set the bits corresponding to single byte chars. */
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ {
+ wint_t wch = __btowc (ch);
+ if (wch != WEOF)
+ dfa->sb_char[i] |= (bitset_word_t) 1 << j;
+# ifndef _LIBC
+ if (isascii (ch) && wch != ch)
+ dfa->map_notascii = 1;
+# endif
+ }
+ }
+ }
+#endif
+
+ if (BE (dfa->nodes == NULL || dfa->state_table == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+/* Initialize WORD_CHAR table, which indicate which character is
+ "word". In this case "word" means that it is the word construction
+ character used by some operators like "\<", "\>", etc. */
+
+static void
+internal_function
+init_word_char (re_dfa_t *dfa)
+{
+ int i, j, ch;
+ dfa->word_ops_used = 1;
+ for (i = 0, ch = 0; i < BITSET_WORDS; ++i)
+ for (j = 0; j < BITSET_WORD_BITS; ++j, ++ch)
+ if (isalnum (ch) || ch == '_')
+ dfa->word_char[i] |= (bitset_word_t) 1 << j;
+}
+
+/* Free the work area which are only used while compiling. */
+
+static void
+free_workarea_compile (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_storage_t *storage, *next;
+ for (storage = dfa->str_tree_storage; storage; storage = next)
+ {
+ next = storage->next;
+ re_free (storage);
+ }
+ dfa->str_tree_storage = NULL;
+ dfa->str_tree_storage_idx = BIN_TREE_STORAGE_SIZE;
+ dfa->str_tree = NULL;
+ re_free (dfa->org_indices);
+ dfa->org_indices = NULL;
+}
+
+/* Create initial states for all contexts. */
+
+static reg_errcode_t
+create_initial_state (re_dfa_t *dfa)
+{
+ int first, i;
+ reg_errcode_t err;
+ re_node_set init_nodes;
+
+ /* Initial states have the epsilon closure of the node which is
+ the first node of the regular expression. */
+ first = dfa->str_tree->first->node_idx;
+ dfa->init_node = first;
+ err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* The back-references which are in initial states can epsilon transit,
+ since in this case all of the subexpressions can be null.
+ Then we add epsilon closures of the nodes which are the next nodes of
+ the back-references. */
+ if (dfa->nbackref > 0)
+ for (i = 0; i < init_nodes.nelem; ++i)
+ {
+ int node_idx = init_nodes.elems[i];
+ re_token_type_t type = dfa->nodes[node_idx].type;
+
+ int clexp_idx;
+ if (type != OP_BACK_REF)
+ continue;
+ for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx)
+ {
+ re_token_t *clexp_node;
+ clexp_node = dfa->nodes + init_nodes.elems[clexp_idx];
+ if (clexp_node->type == OP_CLOSE_SUBEXP
+ && clexp_node->opr.idx == dfa->nodes[node_idx].opr.idx)
+ break;
+ }
+ if (clexp_idx == init_nodes.nelem)
+ continue;
+
+ if (type == OP_BACK_REF)
+ {
+ int dest_idx = dfa->edests[node_idx].elems[0];
+ if (!re_node_set_contains (&init_nodes, dest_idx))
+ {
+ re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+ i = 0;
+ }
+ }
+ }
+
+ /* It must be the first time to invoke acquire_state. */
+ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+ /* We don't check ERR here, since the initial state must not be NULL. */
+ if (BE (dfa->init_state == NULL, 0))
+ return err;
+ if (dfa->init_state->has_constraint)
+ {
+ dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_WORD);
+ dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes,
+ CONTEXT_NEWLINE);
+ dfa->init_state_begbuf = re_acquire_state_context (&err, dfa,
+ &init_nodes,
+ CONTEXT_NEWLINE
+ | CONTEXT_BEGBUF);
+ if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return err;
+ }
+ else
+ dfa->init_state_word = dfa->init_state_nl
+ = dfa->init_state_begbuf = dfa->init_state;
+
+ re_node_set_free (&init_nodes);
+ return REG_NOERROR;
+}
+
+#ifdef RE_ENABLE_I18N
+/* If it is possible to do searching in single byte encoding instead of UTF-8
+ to speed things up, set dfa->mb_cur_max to 1, clear is_utf8 and change
+ DFA nodes where needed. */
+
+static void
+optimize_utf8 (re_dfa_t *dfa)
+{
+ int node, i, mb_chars = 0, has_period = 0;
+
+ for (node = 0; node < dfa->nodes_len; ++node)
+ switch (dfa->nodes[node].type)
+ {
+ case CHARACTER:
+ if (dfa->nodes[node].opr.c >= 0x80)
+ mb_chars = 1;
+ break;
+ case ANCHOR:
+ switch (dfa->nodes[node].opr.idx)
+ {
+ case LINE_FIRST:
+ case LINE_LAST:
+ case BUF_FIRST:
+ case BUF_LAST:
+ break;
+ default:
+ /* Word anchors etc. cannot be handled. */
+ return;
+ }
+ break;
+ case OP_PERIOD:
+ has_period = 1;
+ break;
+ case OP_BACK_REF:
+ case OP_ALT:
+ case END_OF_RE:
+ case OP_DUP_ASTERISK:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ break;
+ case COMPLEX_BRACKET:
+ return;
+ case SIMPLE_BRACKET:
+ /* Just double check. The non-ASCII range starts at 0x80. */
+ assert (0x80 % BITSET_WORD_BITS == 0);
+ for (i = 0x80 / BITSET_WORD_BITS; i < BITSET_WORDS; ++i)
+ if (dfa->nodes[node].opr.sbcset[i])
+ return;
+ break;
+ default:
+ abort ();
+ }
+
+ if (mb_chars || has_period)
+ for (node = 0; node < dfa->nodes_len; ++node)
+ {
+ if (dfa->nodes[node].type == CHARACTER
+ && dfa->nodes[node].opr.c >= 0x80)
+ dfa->nodes[node].mb_partial = 0;
+ else if (dfa->nodes[node].type == OP_PERIOD)
+ dfa->nodes[node].type = OP_UTF8_PERIOD;
+ }
+
+ /* The search can be in single byte locale. */
+ dfa->mb_cur_max = 1;
+ dfa->is_utf8 = 0;
+ dfa->has_mb_node = dfa->nbackref > 0 || has_period;
+}
+#endif
+
+/* Analyze the structure tree, and calculate "first", "next", "edest",
+ "eclosure", and "inveclosure". */
+
+static reg_errcode_t
+analyze (regex_t *preg)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ reg_errcode_t ret;
+
+ /* Allocate arrays. */
+ dfa->nexts = re_malloc (int, dfa->nodes_alloc);
+ dfa->org_indices = re_malloc (int, dfa->nodes_alloc);
+ dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc);
+ dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc);
+ if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL
+ || dfa->eclosures == NULL, 0))
+ return REG_ESPACE;
+
+ dfa->subexp_map = re_malloc (int, preg->re_nsub);
+ if (dfa->subexp_map != NULL)
+ {
+ int i;
+ for (i = 0; i < preg->re_nsub; i++)
+ dfa->subexp_map[i] = i;
+ preorder (dfa->str_tree, optimize_subexps, dfa);
+ for (i = 0; i < preg->re_nsub; i++)
+ if (dfa->subexp_map[i] != i)
+ break;
+ if (i == preg->re_nsub)
+ {
+ free (dfa->subexp_map);
+ dfa->subexp_map = NULL;
+ }
+ }
+
+ ret = postorder (dfa->str_tree, lower_subexps, preg);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = postorder (dfa->str_tree, calc_first, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ preorder (dfa->str_tree, calc_next, dfa);
+ ret = preorder (dfa->str_tree, link_nfa_nodes, dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ ret = calc_eclosure (dfa);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ /* We only need this during the prune_impossible_nodes pass in regexec.c;
+ skip it if p_i_n will not run, as calc_inveclosure can be quadratic. */
+ if ((!preg->no_sub && preg->re_nsub > 0 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_len);
+ if (BE (dfa->inveclosures == NULL, 0))
+ return REG_ESPACE;
+ ret = calc_inveclosure (dfa);
+ }
+
+ return ret;
+}
+
+/* Our parse trees are very unbalanced, so we cannot use a stack to
+ implement parse tree visits. Instead, we use parent pointers and
+ some hairy code in these two functions. */
+static reg_errcode_t
+postorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node, *prev;
+
+ for (node = root; ; )
+ {
+ /* Descend down the tree, preferably to the left (or to the right
+ if that's the only child). */
+ while (node->left || node->right)
+ if (node->left)
+ node = node->left;
+ else
+ node = node->right;
+
+ do
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ if (node->parent == NULL)
+ return REG_NOERROR;
+ prev = node;
+ node = node->parent;
+ }
+ /* Go up while we have a node that is reached from the right. */
+ while (node->right == prev || node->right == NULL);
+ node = node->right;
+ }
+}
+
+static reg_errcode_t
+preorder (bin_tree_t *root, reg_errcode_t (fn (void *, bin_tree_t *)),
+ void *extra)
+{
+ bin_tree_t *node;
+
+ for (node = root; ; )
+ {
+ reg_errcode_t err = fn (extra, node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ node = node->left;
+ else
+ {
+ bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ if (!node)
+ return REG_NOERROR;
+ }
+ node = node->right;
+ }
+ }
+}
+
+/* Optimization pass: if a SUBEXP is entirely contained, strip it and tell
+ re_search_internal to map the inner one's opr.idx to this one's. Adjust
+ backreferences as well. Requires a preorder visit. */
+static reg_errcode_t
+optimize_subexps (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+
+ if (node->token.type == OP_BACK_REF && dfa->subexp_map)
+ {
+ int idx = node->token.opr.idx;
+ node->token.opr.idx = dfa->subexp_map[idx];
+ dfa->used_bkref_map |= 1 << node->token.opr.idx;
+ }
+
+ else if (node->token.type == SUBEXP
+ && node->left && node->left->token.type == SUBEXP)
+ {
+ int other_idx = node->left->token.opr.idx;
+
+ node->left = node->left->left;
+ if (node->left)
+ node->left->parent = node;
+
+ dfa->subexp_map[other_idx] = dfa->subexp_map[node->token.opr.idx];
+ if (other_idx < BITSET_WORD_BITS)
+ dfa->used_bkref_map &= ~((bitset_word_t) 1 << other_idx);
+ }
+
+ return REG_NOERROR;
+}
+
+/* Lowering pass: Turn each SUBEXP node into the appropriate concatenation
+ of OP_OPEN_SUBEXP, the body of the SUBEXP (if any) and OP_CLOSE_SUBEXP. */
+static reg_errcode_t
+lower_subexps (void *extra, bin_tree_t *node)
+{
+ regex_t *preg = (regex_t *) extra;
+ reg_errcode_t err = REG_NOERROR;
+
+ if (node->left && node->left->token.type == SUBEXP)
+ {
+ node->left = lower_subexp (&err, preg, node->left);
+ if (node->left)
+ node->left->parent = node;
+ }
+ if (node->right && node->right->token.type == SUBEXP)
+ {
+ node->right = lower_subexp (&err, preg, node->right);
+ if (node->right)
+ node->right->parent = node;
+ }
+
+ return err;
+}
+
+static bin_tree_t *
+lower_subexp (reg_errcode_t *err, regex_t *preg, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *body = node->left;
+ bin_tree_t *op, *cls, *tree1, *tree;
+
+ if (preg->no_sub
+ /* We do not optimize empty subexpressions, because otherwise we may
+ have bad CONCAT nodes with NULL children. This is obviously not
+ very common, so we do not lose much. An example that triggers
+ this case is the sed "script" /\(\)/x. */
+ && node->left != NULL
+ && (node->token.opr.idx >= BITSET_WORD_BITS
+ || !(dfa->used_bkref_map
+ & ((bitset_word_t) 1 << node->token.opr.idx))))
+ return node->left;
+
+ /* Convert the SUBEXP node to the concatenation of an
+ OP_OPEN_SUBEXP, the contents, and an OP_CLOSE_SUBEXP. */
+ op = create_tree (dfa, NULL, NULL, OP_OPEN_SUBEXP);
+ cls = create_tree (dfa, NULL, NULL, OP_CLOSE_SUBEXP);
+ tree1 = body ? create_tree (dfa, body, cls, CONCAT) : cls;
+ tree = create_tree (dfa, op, tree1, CONCAT);
+ if (BE (tree == NULL || tree1 == NULL || op == NULL || cls == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ op->token.opr.idx = cls->token.opr.idx = node->token.opr.idx;
+ op->token.opt_subexp = cls->token.opt_subexp = node->token.opt_subexp;
+ return tree;
+}
+
+/* Pass 1 in building the NFA: compute FIRST and create unlinked automaton
+ nodes. Requires a postorder visit. */
+static reg_errcode_t
+calc_first (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ if (node->token.type == CONCAT)
+ {
+ node->first = node->left->first;
+ node->node_idx = node->left->node_idx;
+ }
+ else
+ {
+ node->first = node;
+ node->node_idx = re_dfa_add_node (dfa, node->token);
+ if (BE (node->node_idx == -1, 0))
+ return REG_ESPACE;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 2: compute NEXT on the tree. Preorder visit. */
+static reg_errcode_t
+calc_next (void *extra, bin_tree_t *node)
+{
+ switch (node->token.type)
+ {
+ case OP_DUP_ASTERISK:
+ node->left->next = node;
+ break;
+ case CONCAT:
+ node->left->next = node->right->first;
+ node->right->next = node->next;
+ break;
+ default:
+ if (node->left)
+ node->left->next = node->next;
+ if (node->right)
+ node->right->next = node->next;
+ break;
+ }
+ return REG_NOERROR;
+}
+
+/* Pass 3: link all DFA nodes to their NEXT node (any order will do). */
+static reg_errcode_t
+link_nfa_nodes (void *extra, bin_tree_t *node)
+{
+ re_dfa_t *dfa = (re_dfa_t *) extra;
+ int idx = node->node_idx;
+ reg_errcode_t err = REG_NOERROR;
+
+ switch (node->token.type)
+ {
+ case CONCAT:
+ break;
+
+ case END_OF_RE:
+ assert (node->next == NULL);
+ break;
+
+ case OP_DUP_ASTERISK:
+ case OP_ALT:
+ {
+ int left, right;
+ dfa->has_plural_match = 1;
+ if (node->left != NULL)
+ left = node->left->first->node_idx;
+ else
+ left = node->next->node_idx;
+ if (node->right != NULL)
+ right = node->right->first->node_idx;
+ else
+ right = node->next->node_idx;
+ assert (left > -1);
+ assert (right > -1);
+ err = re_node_set_init_2 (dfa->edests + idx, left, right);
+ }
+ break;
+
+ case ANCHOR:
+ case OP_OPEN_SUBEXP:
+ case OP_CLOSE_SUBEXP:
+ err = re_node_set_init_1 (dfa->edests + idx, node->next->node_idx);
+ break;
+
+ case OP_BACK_REF:
+ dfa->nexts[idx] = node->next->node_idx;
+ if (node->token.type == OP_BACK_REF)
+ re_node_set_init_1 (dfa->edests + idx, dfa->nexts[idx]);
+ break;
+
+ default:
+ assert (!IS_EPSILON_NODE (node->token.type));
+ dfa->nexts[idx] = node->next->node_idx;
+ break;
+ }
+
+ return err;
+}
+
+/* Duplicate the epsilon closure of the node ROOT_NODE.
+ Note that duplicated nodes have constraint INIT_CONSTRAINT in addition
+ to their own constraint. */
+
+static reg_errcode_t
+internal_function
+duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node,
+ int root_node, unsigned int init_constraint)
+{
+ int org_node, clone_node, ret;
+ unsigned int constraint = init_constraint;
+ for (org_node = top_org_node, clone_node = top_clone_node;;)
+ {
+ int org_dest, clone_dest;
+ if (dfa->nodes[org_node].type == OP_BACK_REF)
+ {
+ /* If the back reference epsilon-transit, its destination must
+ also have the constraint. Then duplicate the epsilon closure
+ of the destination of the back reference, and store it in
+ edests of the back reference. */
+ org_dest = dfa->nexts[org_node];
+ re_node_set_empty (dfa->edests + clone_node);
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else if (dfa->edests[org_node].nelem == 0)
+ {
+ /* In case of the node can't epsilon-transit, don't duplicate the
+ destination and store the original destination as the
+ destination of the node. */
+ dfa->nexts[clone_node] = dfa->nexts[org_node];
+ break;
+ }
+ else if (dfa->edests[org_node].nelem == 1)
+ {
+ /* In case of the node can epsilon-transit, and it has only one
+ destination. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ if (dfa->nodes[org_node].type == ANCHOR)
+ {
+ /* In case of the node has another constraint, append it. */
+ if (org_node == root_node && clone_node != org_node)
+ {
+ /* ...but if the node is root_node itself, it means the
+ epsilon closure have a loop, then tie it to the
+ destination of the root_node. */
+ ret = re_node_set_insert (dfa->edests + clone_node,
+ org_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ break;
+ }
+ constraint |= dfa->nodes[org_node].opr.ctx_type;
+ }
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ else /* dfa->edests[org_node].nelem == 2 */
+ {
+ /* In case of the node can epsilon-transit, and it has two
+ destinations. In the bin_tree_t and DFA, that's '|' and '*'. */
+ org_dest = dfa->edests[org_node].elems[0];
+ re_node_set_empty (dfa->edests + clone_node);
+ /* Search for a duplicated node which satisfies the constraint. */
+ clone_dest = search_duplicated_node (dfa, org_dest, constraint);
+ if (clone_dest == -1)
+ {
+ /* There are no such a duplicated node, create a new one. */
+ reg_errcode_t err;
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ err = duplicate_node_closure (dfa, org_dest, clone_dest,
+ root_node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ {
+ /* There are a duplicated node which satisfy the constraint,
+ use it to avoid infinite loop. */
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+
+ org_dest = dfa->edests[org_node].elems[1];
+ clone_dest = duplicate_node (dfa, org_dest, constraint);
+ if (BE (clone_dest == -1, 0))
+ return REG_ESPACE;
+ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest);
+ if (BE (ret < 0, 0))
+ return REG_ESPACE;
+ }
+ org_node = org_dest;
+ clone_node = clone_dest;
+ }
+ return REG_NOERROR;
+}
+
+/* Search for a node which is duplicated from the node ORG_NODE, and
+ satisfies the constraint CONSTRAINT. */
+
+static int
+search_duplicated_node (const re_dfa_t *dfa, int org_node,
+ unsigned int constraint)
+{
+ int idx;
+ for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx)
+ {
+ if (org_node == dfa->org_indices[idx]
+ && constraint == dfa->nodes[idx].constraint)
+ return idx; /* Found. */
+ }
+ return -1; /* Not found. */
+}
+
+/* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT.
+ Return the index of the new node, or -1 if insufficient storage is
+ available. */
+
+static int
+duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint)
+{
+ int dup_idx = re_dfa_add_node (dfa, dfa->nodes[org_idx]);
+ if (BE (dup_idx != -1, 1))
+ {
+ dfa->nodes[dup_idx].constraint = constraint;
+ if (dfa->nodes[org_idx].type == ANCHOR)
+ dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type;
+ dfa->nodes[dup_idx].duplicated = 1;
+
+ /* Store the index of the original node. */
+ dfa->org_indices[dup_idx] = org_idx;
+ }
+ return dup_idx;
+}
+
+static reg_errcode_t
+calc_inveclosure (re_dfa_t *dfa)
+{
+ int src, idx, ret;
+ for (idx = 0; idx < dfa->nodes_len; ++idx)
+ re_node_set_init_empty (dfa->inveclosures + idx);
+
+ for (src = 0; src < dfa->nodes_len; ++src)
+ {
+ int *elems = dfa->eclosures[src].elems;
+ for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx)
+ {
+ ret = re_node_set_insert_last (dfa->inveclosures + elems[idx], src);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Calculate "eclosure" for all the node in DFA. */
+
+static reg_errcode_t
+calc_eclosure (re_dfa_t *dfa)
+{
+ int node_idx, incomplete;
+#ifdef DEBUG
+ assert (dfa->nodes_len > 0);
+#endif
+ incomplete = 0;
+ /* For each nodes, calculate epsilon closure. */
+ for (node_idx = 0; ; ++node_idx)
+ {
+ reg_errcode_t err;
+ re_node_set eclosure_elem;
+ if (node_idx == dfa->nodes_len)
+ {
+ if (!incomplete)
+ break;
+ incomplete = 0;
+ node_idx = 0;
+ }
+
+#ifdef DEBUG
+ assert (dfa->eclosures[node_idx].nelem != -1);
+#endif
+
+ /* If we have already calculated, skip it. */
+ if (dfa->eclosures[node_idx].nelem != 0)
+ continue;
+ /* Calculate epsilon closure of `node_idx'. */
+ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (dfa->eclosures[node_idx].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Calculate epsilon closure of NODE. */
+
+static reg_errcode_t
+calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root)
+{
+ reg_errcode_t err;
+ unsigned int constraint;
+ int i, incomplete;
+ re_node_set eclosure;
+ incomplete = 0;
+ err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* This indicates that we are calculating this node now.
+ We reference this value to avoid infinite loop. */
+ dfa->eclosures[node].nelem = -1;
+
+ constraint = ((dfa->nodes[node].type == ANCHOR)
+ ? dfa->nodes[node].opr.ctx_type : 0);
+ /* If the current node has constraints, duplicate all nodes.
+ Since they must inherit the constraints. */
+ if (constraint
+ && dfa->edests[node].nelem
+ && !dfa->nodes[dfa->edests[node].elems[0]].duplicated)
+ {
+ err = duplicate_node_closure (dfa, node, node, node, constraint);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Expand each epsilon destination nodes. */
+ if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ for (i = 0; i < dfa->edests[node].nelem; ++i)
+ {
+ re_node_set eclosure_elem;
+ int edest = dfa->edests[node].elems[i];
+ /* If calculating the epsilon closure of `edest' is in progress,
+ return intermediate result. */
+ if (dfa->eclosures[edest].nelem == -1)
+ {
+ incomplete = 1;
+ continue;
+ }
+ /* If we haven't calculated the epsilon closure of `edest' yet,
+ calculate now. Otherwise use calculated epsilon closure. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ eclosure_elem = dfa->eclosures[edest];
+ /* Merge the epsilon closure of `edest'. */
+ re_node_set_merge (&eclosure, &eclosure_elem);
+ /* If the epsilon closure of `edest' is incomplete,
+ the epsilon closure of this node is also incomplete. */
+ if (dfa->eclosures[edest].nelem == 0)
+ {
+ incomplete = 1;
+ re_node_set_free (&eclosure_elem);
+ }
+ }
+
+ /* Epsilon closures include itself. */
+ re_node_set_insert (&eclosure, node);
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ return REG_NOERROR;
+}
+
+/* Functions for token which are used in the parser. */
+
+/* Fetch a token from INPUT.
+ We must not use this function inside bracket expressions. */
+
+static void
+internal_function
+fetch_token (re_token_t *result, re_string_t *input, reg_syntax_t syntax)
+{
+ re_string_skip_bytes (input, peek_token (result, input, syntax));
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function inside bracket expressions. */
+
+static int
+internal_function
+peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+ token->word_char = 0;
+#ifdef RE_ENABLE_I18N
+ token->mb_partial = 0;
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ token->mb_partial = 1;
+ return 1;
+ }
+#endif
+ if (c == '\\')
+ {
+ unsigned char c2;
+ if (re_string_cur_idx (input) + 1 >= re_string_length (input))
+ {
+ token->type = BACK_SLASH;
+ return 1;
+ }
+
+ c2 = re_string_peek_byte_case (input, 1);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input,
+ re_string_cur_idx (input) + 1);
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (c2) != 0;
+
+ switch (c2)
+ {
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (!(syntax & RE_NO_BK_REFS))
+ {
+ token->type = OP_BACK_REF;
+ token->opr.idx = c2 - '1';
+ }
+ break;
+ case '<':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_FIRST;
+ }
+ break;
+ case '>':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_LAST;
+ }
+ break;
+ case 'b':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = WORD_DELIM;
+ }
+ break;
+ case 'B':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = NOT_WORD_DELIM;
+ }
+ break;
+ case 'w':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_WORD;
+ break;
+ case 'W':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTWORD;
+ break;
+ case 's':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_SPACE;
+ break;
+ case 'S':
+ if (!(syntax & RE_NO_GNU_OPS))
+ token->type = OP_NOTSPACE;
+ break;
+ case '`':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_FIRST;
+ }
+ break;
+ case '\'':
+ if (!(syntax & RE_NO_GNU_OPS))
+ {
+ token->type = ANCHOR;
+ token->opr.ctx_type = BUF_LAST;
+ }
+ break;
+ case '(':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (!(syntax & RE_NO_BK_PARENS))
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES)))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ default:
+ break;
+ }
+ return 2;
+ }
+
+ token->type = CHARACTER;
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc = re_string_wchar_at (input, re_string_cur_idx (input));
+ token->word_char = IS_WIDE_WORD_CHAR (wc) != 0;
+ }
+ else
+#endif
+ token->word_char = IS_WORD_CHAR (token->opr.c);
+
+ switch (c)
+ {
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ token->type = OP_ALT;
+ break;
+ case '|':
+ if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR))
+ token->type = OP_ALT;
+ break;
+ case '*':
+ token->type = OP_DUP_ASTERISK;
+ break;
+ case '+':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_PLUS;
+ break;
+ case '?':
+ if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM))
+ token->type = OP_DUP_QUESTION;
+ break;
+ case '{':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_OPEN_DUP_NUM;
+ break;
+ case '}':
+ if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ token->type = OP_CLOSE_DUP_NUM;
+ break;
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_OPEN_SUBEXP;
+ break;
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ token->type = OP_CLOSE_SUBEXP;
+ break;
+ case '[':
+ token->type = OP_OPEN_BRACKET;
+ break;
+ case '.':
+ token->type = OP_PERIOD;
+ break;
+ case '^':
+ if (!(syntax & (RE_CONTEXT_INDEP_ANCHORS | RE_CARET_ANCHORS_HERE)) &&
+ re_string_cur_idx (input) != 0)
+ {
+ char prev = re_string_peek_byte (input, -1);
+ if (!(syntax & RE_NEWLINE_ALT) || prev != '\n')
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_FIRST;
+ break;
+ case '$':
+ if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) &&
+ re_string_cur_idx (input) + 1 != re_string_length (input))
+ {
+ re_token_t next;
+ re_string_skip_bytes (input, 1);
+ peek_token (&next, input, syntax);
+ re_string_skip_bytes (input, -1);
+ if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP)
+ break;
+ }
+ token->type = ANCHOR;
+ token->opr.ctx_type = LINE_LAST;
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Peek a token from INPUT, and return the length of the token.
+ We must not use this function out of bracket expressions. */
+
+static int
+internal_function
+peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
+{
+ unsigned char c;
+ if (re_string_eoi (input))
+ {
+ token->type = END_OF_RE;
+ return 0;
+ }
+ c = re_string_peek_byte (input, 0);
+ token->opr.c = c;
+
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1 &&
+ !re_string_first_byte (input, re_string_cur_idx (input)))
+ {
+ token->type = CHARACTER;
+ return 1;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)
+ && re_string_cur_idx (input) + 1 < re_string_length (input))
+ {
+ /* In this case, '\' escape a character. */
+ unsigned char c2;
+ re_string_skip_bytes (input, 1);
+ c2 = re_string_peek_byte (input, 0);
+ token->opr.c = c2;
+ token->type = CHARACTER;
+ return 1;
+ }
+ if (c == '[') /* '[' is a special char in a bracket exps. */
+ {
+ unsigned char c2;
+ int token_len;
+ if (re_string_cur_idx (input) + 1 < re_string_length (input))
+ c2 = re_string_peek_byte (input, 1);
+ else
+ c2 = 0;
+ token->opr.c = c2;
+ token_len = 2;
+ switch (c2)
+ {
+ case '.':
+ token->type = OP_OPEN_COLL_ELEM;
+ break;
+ case '=':
+ token->type = OP_OPEN_EQUIV_CLASS;
+ break;
+ case ':':
+ if (syntax & RE_CHAR_CLASSES)
+ {
+ token->type = OP_OPEN_CHAR_CLASS;
+ break;
+ }
+ /* else fall through. */
+ default:
+ token->type = CHARACTER;
+ token->opr.c = c;
+ token_len = 1;
+ break;
+ }
+ return token_len;
+ }
+ switch (c)
+ {
+ case '-':
+ token->type = OP_CHARSET_RANGE;
+ break;
+ case ']':
+ token->type = OP_CLOSE_BRACKET;
+ break;
+ case '^':
+ token->type = OP_NON_MATCH_LIST;
+ break;
+ default:
+ token->type = CHARACTER;
+ }
+ return 1;
+}
+
+/* Functions for parser. */
+
+/* Entry point of the parser.
+ Parse the regular expression REGEXP and return the structure tree.
+ If an error is occured, ERR is set by error code, and return NULL.
+ This function build the following tree, from regular expression <reg_exp>:
+ CAT
+ / \
+ / \
+ <reg_exp> EOR
+
+ CAT means concatenation.
+ EOR means end of regular expression. */
+
+static bin_tree_t *
+parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax,
+ reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *eor, *root;
+ re_token_t current_token;
+ dfa->syntax = syntax;
+ fetch_token (&current_token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ tree = parse_reg_exp (regexp, preg, &current_token, syntax, 0, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ eor = create_tree (dfa, NULL, NULL, END_OF_RE);
+ if (tree != NULL)
+ root = create_tree (dfa, tree, eor, CONCAT);
+ else
+ root = eor;
+ if (BE (eor == NULL || root == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ return root;
+}
+
+/* This function build the following tree, from regular expression
+ <branch1>|<branch2>:
+ ALT
+ / \
+ / \
+ <branch1> <branch2>
+
+ ALT means alternative, which represents the operator `|'. */
+
+static bin_tree_t *
+parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree, *branch = NULL;
+ tree = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type == OP_ALT)
+ {
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+ if (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ branch = parse_branch (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && branch == NULL, 0))
+ return NULL;
+ }
+ else
+ branch = NULL;
+ tree = create_tree (dfa, tree, branch, OP_ALT);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ <exp1><exp2>:
+ CAT
+ / \
+ / \
+ <exp1> <exp2>
+
+ CAT means concatenation. */
+
+static bin_tree_t *
+parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ bin_tree_t *tree, *exp;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ tree = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+
+ while (token->type != OP_ALT && token->type != END_OF_RE
+ && (nest == 0 || token->type != OP_CLOSE_SUBEXP))
+ {
+ exp = parse_expression (regexp, preg, token, syntax, nest, err);
+ if (BE (*err != REG_NOERROR && exp == NULL, 0))
+ {
+ return NULL;
+ }
+ if (tree != NULL && exp != NULL)
+ {
+ tree = create_tree (dfa, tree, exp, CONCAT);
+ if (tree == NULL)
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else if (tree == NULL)
+ tree = exp;
+ /* Otherwise exp == NULL, we don't need to create new tree. */
+ }
+ return tree;
+}
+
+/* This function build the following tree, from regular expression a*:
+ *
+ |
+ a
+*/
+
+static bin_tree_t *
+parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ switch (token->type)
+ {
+ case CHARACTER:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (!re_string_eoi (regexp)
+ && !re_string_first_byte (regexp, re_string_cur_idx (regexp)))
+ {
+ bin_tree_t *mbc_remain;
+ fetch_token (token, regexp, syntax);
+ mbc_remain = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree, mbc_remain, CONCAT);
+ if (BE (mbc_remain == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ }
+#endif
+ break;
+ case OP_OPEN_SUBEXP:
+ tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_OPEN_BRACKET:
+ tree = parse_bracket_exp (regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_BACK_REF:
+ if (!BE (dfa->completed_bkref_map & (1 << token->opr.idx), 1))
+ {
+ *err = REG_ESUBREG;
+ return NULL;
+ }
+ dfa->used_bkref_map |= 1 << token->opr.idx;
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ ++dfa->nbackref;
+ dfa->has_mb_node = 1;
+ break;
+ case OP_OPEN_DUP_NUM:
+ if (syntax & RE_CONTEXT_INVALID_DUP)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ /* FALLTHROUGH */
+ case OP_DUP_ASTERISK:
+ case OP_DUP_PLUS:
+ case OP_DUP_QUESTION:
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ {
+ fetch_token (token, regexp, syntax);
+ return parse_expression (regexp, preg, token, syntax, nest, err);
+ }
+ /* else fall through */
+ case OP_CLOSE_SUBEXP:
+ if ((token->type == OP_CLOSE_SUBEXP) &&
+ !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD))
+ {
+ *err = REG_ERPAREN;
+ return NULL;
+ }
+ /* else fall through */
+ case OP_CLOSE_DUP_NUM:
+ /* We treat it as a normal character. */
+
+ /* Then we can these characters as normal characters. */
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be initialized already
+ by peek_token. */
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ break;
+ case ANCHOR:
+ if ((token->opr.ctx_type
+ & (WORD_DELIM | NOT_WORD_DELIM | WORD_FIRST | WORD_LAST))
+ && dfa->word_ops_used == 0)
+ init_word_char (dfa);
+ if (token->opr.ctx_type == WORD_DELIM
+ || token->opr.ctx_type == NOT_WORD_DELIM)
+ {
+ bin_tree_t *tree_first, *tree_last;
+ if (token->opr.ctx_type == WORD_DELIM)
+ {
+ token->opr.ctx_type = WORD_FIRST;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = WORD_LAST;
+ }
+ else
+ {
+ token->opr.ctx_type = INSIDE_WORD;
+ tree_first = create_token_tree (dfa, NULL, NULL, token);
+ token->opr.ctx_type = INSIDE_NOTWORD;
+ }
+ tree_last = create_token_tree (dfa, NULL, NULL, token);
+ tree = create_tree (dfa, tree_first, tree_last, OP_ALT);
+ if (BE (tree_first == NULL || tree_last == NULL || tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ else
+ {
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ }
+ /* We must return here, since ANCHORs can't be followed
+ by repetition operators.
+ eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>",
+ it must not be "<ANCHOR(^)><REPEAT(*)>". */
+ fetch_token (token, regexp, syntax);
+ return tree;
+ case OP_PERIOD:
+ tree = create_token_tree (dfa, NULL, NULL, token);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ if (dfa->mb_cur_max > 1)
+ dfa->has_mb_node = 1;
+ break;
+ case OP_WORD:
+ case OP_NOTWORD:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "alnum",
+ (const unsigned char *) "_",
+ token->type == OP_NOTWORD, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_SPACE:
+ case OP_NOTSPACE:
+ tree = build_charclass_op (dfa, regexp->trans,
+ (const unsigned char *) "space",
+ (const unsigned char *) "",
+ token->type == OP_NOTSPACE, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ break;
+ case OP_ALT:
+ case END_OF_RE:
+ return NULL;
+ case BACK_SLASH:
+ *err = REG_EESCAPE;
+ return NULL;
+ default:
+ /* Must not happen? */
+#ifdef DEBUG
+ assert (0);
+#endif
+ return NULL;
+ }
+ fetch_token (token, regexp, syntax);
+
+ while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS
+ || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM)
+ {
+ tree = parse_dup_op (tree, regexp, dfa, token, syntax, err);
+ if (BE (*err != REG_NOERROR && tree == NULL, 0))
+ return NULL;
+ /* In BRE consecutive duplications are not allowed. */
+ if ((syntax & RE_CONTEXT_INVALID_DUP)
+ && (token->type == OP_DUP_ASTERISK
+ || token->type == OP_OPEN_DUP_NUM))
+ {
+ *err = REG_BADRPT;
+ return NULL;
+ }
+ }
+
+ return tree;
+}
+
+/* This function build the following tree, from regular expression
+ (<reg_exp>):
+ SUBEXP
+ |
+ <reg_exp>
+*/
+
+static bin_tree_t *
+parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token,
+ reg_syntax_t syntax, int nest, reg_errcode_t *err)
+{
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+ bin_tree_t *tree;
+ size_t cur_nsub;
+ cur_nsub = preg->re_nsub++;
+
+ fetch_token (token, regexp, syntax | RE_CARET_ANCHORS_HERE);
+
+ /* The subexpression may be a null string. */
+ if (token->type == OP_CLOSE_SUBEXP)
+ tree = NULL;
+ else
+ {
+ tree = parse_reg_exp (regexp, preg, token, syntax, nest, err);
+ if (BE (*err == REG_NOERROR && token->type != OP_CLOSE_SUBEXP, 0))
+ *err = REG_EPAREN;
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+
+ if (cur_nsub <= '9' - '1')
+ dfa->completed_bkref_map |= 1 << cur_nsub;
+
+ tree = create_tree (dfa, tree, NULL, SUBEXP);
+ if (BE (tree == NULL, 0))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+ tree->token.opr.idx = cur_nsub;
+ return tree;
+}
+
+/* This function parse repetition operators like "*", "+", "{1,3}" etc. */
+
+static bin_tree_t *
+parse_dup_op (bin_tree_t *elem, re_string_t *regexp, re_dfa_t *dfa,
+ re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err)
+{
+ bin_tree_t *tree = NULL, *old_tree = NULL;
+ int i, start, end, start_idx = re_string_cur_idx (regexp);
+ re_token_t start_token = *token;
+
+ if (token->type == OP_OPEN_DUP_NUM)
+ {
+ end = 0;
+ start = fetch_number (regexp, token, syntax);
+ if (start == -1)
+ {
+ if (token->type == CHARACTER && token->opr.c == ',')
+ start = 0; /* We treat "{,m}" as "{0,m}". */
+ else
+ {
+ *err = REG_BADBR; /* <re>{} is invalid. */
+ return NULL;
+ }
+ }
+ if (BE (start != -2, 1))
+ {
+ /* We treat "{n}" as "{n,n}". */
+ end = ((token->type == OP_CLOSE_DUP_NUM) ? start
+ : ((token->type == CHARACTER && token->opr.c == ',')
+ ? fetch_number (regexp, token, syntax) : -2));
+ }
+ if (BE (start == -2 || end == -2, 0))
+ {
+ /* Invalid sequence. */
+ if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0))
+ {
+ if (token->type == END_OF_RE)
+ *err = REG_EBRACE;
+ else
+ *err = REG_BADBR;
+
+ return NULL;
+ }
+
+ /* If the syntax bit is set, rollback. */
+ re_string_set_index (regexp, start_idx);
+ *token = start_token;
+ token->type = CHARACTER;
+ /* mb_partial and word_char bits should be already initialized by
+ peek_token. */
+ return elem;
+ }
+
+ if (BE (end != -1 && start > end, 0))
+ {
+ /* First number greater than second. */
+ *err = REG_BADBR;
+ return NULL;
+ }
+ }
+ else
+ {
+ start = (token->type == OP_DUP_PLUS) ? 1 : 0;
+ end = (token->type == OP_DUP_QUESTION) ? 1 : -1;
+ }
+
+ fetch_token (token, regexp, syntax);
+
+ if (BE (elem == NULL, 0))
+ return NULL;
+ if (BE (start == 0 && end == 0, 0))
+ {
+ postorder (elem, free_tree, NULL);
+ return NULL;
+ }
+
+ /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */
+ if (BE (start > 0, 0))
+ {
+ tree = elem;
+ for (i = 2; i <= start; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (start == end)
+ return tree;
+
+ /* Duplicate ELEM before it is marked optional. */
+ elem = duplicate_tree (elem, dfa);
+ old_tree = tree;
+ }
+ else
+ old_tree = NULL;
+
+ if (elem->token.type == SUBEXP)
+ postorder (elem, mark_opt_subexp, (void *) (long) elem->token.opr.idx);
+
+ tree = create_tree (dfa, elem, NULL, (end == -1 ? OP_DUP_ASTERISK : OP_ALT));
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ /* This loop is actually executed only when end != -1,
+ to rewrite <re>{0,n} as (<re>(<re>...<re>?)?)?... We have
+ already created the start+1-th copy. */
+ for (i = start + 2; i <= end; ++i)
+ {
+ elem = duplicate_tree (elem, dfa);
+ tree = create_tree (dfa, tree, elem, CONCAT);
+ if (BE (elem == NULL || tree == NULL, 0))
+ goto parse_dup_op_espace;
+
+ tree = create_tree (dfa, tree, NULL, OP_ALT);
+ if (BE (tree == NULL, 0))
+ goto parse_dup_op_espace;
+ }
+
+ if (old_tree)
+ tree = create_tree (dfa, old_tree, tree, CONCAT);
+
+ return tree;
+
+ parse_dup_op_espace:
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* Size of the names for collating symbol/equivalence_class/character_class.
+ I'm not sure, but maybe enough. */
+#define BRACKET_NAME_BUF_SIZE 32
+
+#ifndef _LIBC
+ /* Local function for parse_bracket_exp only used in case of NOT _LIBC.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_range_exp (bitset_t sbcset, re_charset_t *mbcset, int *range_alloc,
+ bracket_elem_t *start_elem, bracket_elem_t *end_elem)
+# else /* not RE_ENABLE_I18N */
+build_range_exp (bitset_t sbcset, bracket_elem_t *start_elem,
+ bracket_elem_t *end_elem)
+# endif /* not RE_ENABLE_I18N */
+{
+ unsigned int start_ch, end_ch;
+ /* Equivalence Classes and Character Classes can't be a range start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ /* We can handle no multi character collating elements without libc
+ support. */
+ if (BE ((start_elem->type == COLL_SYM
+ && strlen ((char *) start_elem->opr.name) > 1)
+ || (end_elem->type == COLL_SYM
+ && strlen ((char *) end_elem->opr.name) > 1), 0))
+ return REG_ECOLLATE;
+
+# ifdef RE_ENABLE_I18N
+ {
+ wchar_t wc;
+ wint_t start_wc;
+ wint_t end_wc;
+ wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+
+ start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM)
+ ? __btowc (start_ch) : start_elem->opr.wch);
+ end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM)
+ ? __btowc (end_ch) : end_elem->opr.wch);
+ if (start_wc == WEOF || end_wc == WEOF)
+ return REG_ECOLLATE;
+ cmp_buf[0] = start_wc;
+ cmp_buf[4] = end_wc;
+ if (wcscoll (cmp_buf, cmp_buf + 4) > 0)
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, for !_LIBC we have no collation elements: if the
+ character set is single byte, the single byte character set
+ that we build below suffices. parse_bracket_exp passes
+ no MBCSET if dfa->mb_cur_max == 1. */
+ if (mbcset)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ wchar_t *new_array_start, *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ /* Use realloc since mbcset->range_starts and mbcset->range_ends
+ are NULL if *range_alloc == 0. */
+ new_array_start = re_realloc (mbcset->range_starts, wchar_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, wchar_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_wc;
+ mbcset->range_ends[mbcset->nranges++] = end_wc;
+ }
+
+ /* Build the table for single byte characters. */
+ for (wc = 0; wc < SBC_MAX; ++wc)
+ {
+ cmp_buf[2] = wc;
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ bitset_set (sbcset, wc);
+ }
+ }
+# else /* not RE_ENABLE_I18N */
+ {
+ unsigned int ch;
+ start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch
+ : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0]
+ : 0));
+ end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch
+ : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0]
+ : 0));
+ if (start_ch > end_ch)
+ return REG_ERANGE;
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ if (start_ch <= ch && ch <= end_ch)
+ bitset_set (sbcset, ch);
+ }
+# endif /* not RE_ENABLE_I18N */
+ return REG_NOERROR;
+}
+#endif /* not _LIBC */
+
+#ifndef _LIBC
+/* Helper function for parse_bracket_exp only used in case of NOT _LIBC..
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument since we may update it. */
+
+static reg_errcode_t
+internal_function
+# ifdef RE_ENABLE_I18N
+build_collating_symbol (bitset_t sbcset, re_charset_t *mbcset,
+ int *coll_sym_alloc, const unsigned char *name)
+# else /* not RE_ENABLE_I18N */
+build_collating_symbol (bitset_t sbcset, const unsigned char *name)
+# endif /* not RE_ENABLE_I18N */
+{
+ size_t name_len = strlen ((const char *) name);
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+}
+#endif /* not _LIBC */
+
+/* This function parse bracket expression like "[abc]", "[a-c]",
+ "[[.a-a.]]" etc. */
+
+static bin_tree_t *
+parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
+ reg_syntax_t syntax, reg_errcode_t *err)
+{
+#ifdef _LIBC
+ const unsigned char *collseqmb;
+ const char *collseqwc;
+ uint32_t nrules;
+ int32_t table_size;
+ const int32_t *symb_table;
+ const unsigned char *extra;
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Seek the collating symbol entry correspondings to NAME.
+ Return the index of the symbol in the SYMB_TABLE. */
+
+ auto inline int32_t
+ __attribute ((always_inline))
+ seek_collating_symbol_entry (name, name_len)
+ const unsigned char *name;
+ size_t name_len;
+ {
+ int32_t hash = elem_hash ((const char *) name, name_len);
+ int32_t elem = hash % table_size;
+ if (symb_table[2 * elem] != 0)
+ {
+ int32_t second = hash % (table_size - 2) + 1;
+
+ do
+ {
+ /* First compare the hashing value. */
+ if (symb_table[2 * elem] == hash
+ /* Compare the length of the name. */
+ && name_len == extra[symb_table[2 * elem + 1]]
+ /* Compare the name. */
+ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1],
+ name_len) == 0)
+ {
+ /* Yep, this is the entry. */
+ break;
+ }
+
+ /* Next entry. */
+ elem += second;
+ }
+ while (symb_table[2 * elem] != 0);
+ }
+ return elem;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Look up the collation sequence value of BR_ELEM.
+ Return the value if succeeded, UINT_MAX otherwise. */
+
+ auto inline unsigned int
+ __attribute ((always_inline))
+ lookup_collation_sequence_value (br_elem)
+ bracket_elem_t *br_elem;
+ {
+ if (br_elem->type == SB_CHAR)
+ {
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ return collseqmb[br_elem->opr.ch];
+ else
+ {
+ wint_t wc = __btowc (br_elem->opr.ch);
+ return __collseq_table_lookup (collseqwc, wc);
+ }
+ }
+ else if (br_elem->type == MB_CHAR)
+ {
+ return __collseq_table_lookup (collseqwc, br_elem->opr.wch);
+ }
+ else if (br_elem->type == COLL_SYM)
+ {
+ size_t sym_name_len = strlen ((char *) br_elem->opr.name);
+ if (nrules != 0)
+ {
+ int32_t elem, idx;
+ elem = seek_collating_symbol_entry (br_elem->opr.name,
+ sym_name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ /* Skip the byte sequence of the collating element. */
+ idx += 1 + extra[idx];
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the multibyte collation sequence value. */
+ idx += sizeof (unsigned int);
+ /* Skip the wide char sequence of the collating element. */
+ idx += sizeof (unsigned int) *
+ (1 + *(unsigned int *) (extra + idx));
+ /* Return the collation sequence value. */
+ return *(unsigned int *) (extra + idx);
+ }
+ else if (symb_table[2 * elem] == 0 && sym_name_len == 1)
+ {
+ /* No valid character. Match it as a single byte
+ character. */
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ }
+ else if (sym_name_len == 1)
+ return collseqmb[br_elem->opr.name[0]];
+ }
+ return UINT_MAX;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the range expression which starts from START_ELEM, and ends
+ at END_ELEM. The result are written to MBCSET and SBCSET.
+ RANGE_ALLOC is the allocated size of mbcset->range_starts, and
+ mbcset->range_ends, is a pointer argument sinse we may
+ update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem)
+ re_charset_t *mbcset;
+ int *range_alloc;
+ bitset_t sbcset;
+ bracket_elem_t *start_elem, *end_elem;
+ {
+ unsigned int ch;
+ uint32_t start_collseq;
+ uint32_t end_collseq;
+
+ /* Equivalence Classes and Character Classes can't be a range
+ start/end. */
+ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS
+ || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS,
+ 0))
+ return REG_ERANGE;
+
+ start_collseq = lookup_collation_sequence_value (start_elem);
+ end_collseq = lookup_collation_sequence_value (end_elem);
+ /* Check start/end collation sequence values. */
+ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0))
+ return REG_ECOLLATE;
+ if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0))
+ return REG_ERANGE;
+
+ /* Got valid collation sequence values, add them as a new entry.
+ However, if we have no collation elements, and the character set
+ is single byte, the single byte character set that we
+ build below suffices. */
+ if (nrules > 0 || dfa->mb_cur_max > 1)
+ {
+ /* Check the space of the arrays. */
+ if (BE (*range_alloc == mbcset->nranges, 0))
+ {
+ /* There is not enough space, need realloc. */
+ uint32_t *new_array_start;
+ uint32_t *new_array_end;
+ int new_nranges;
+
+ /* +1 in case of mbcset->nranges is 0. */
+ new_nranges = 2 * mbcset->nranges + 1;
+ new_array_start = re_realloc (mbcset->range_starts, uint32_t,
+ new_nranges);
+ new_array_end = re_realloc (mbcset->range_ends, uint32_t,
+ new_nranges);
+
+ if (BE (new_array_start == NULL || new_array_end == NULL, 0))
+ return REG_ESPACE;
+
+ mbcset->range_starts = new_array_start;
+ mbcset->range_ends = new_array_end;
+ *range_alloc = new_nranges;
+ }
+
+ mbcset->range_starts[mbcset->nranges] = start_collseq;
+ mbcset->range_ends[mbcset->nranges++] = end_collseq;
+ }
+
+ /* Build the table for single byte characters. */
+ for (ch = 0; ch < SBC_MAX; ch++)
+ {
+ uint32_t ch_collseq;
+ /*
+ if (MB_CUR_MAX == 1)
+ */
+ if (nrules == 0)
+ ch_collseq = collseqmb[ch];
+ else
+ ch_collseq = __collseq_table_lookup (collseqwc, __btowc (ch));
+ if (start_collseq <= ch_collseq && ch_collseq <= end_collseq)
+ bitset_set (sbcset, ch);
+ }
+ return REG_NOERROR;
+ }
+
+ /* Local function for parse_bracket_exp used in _LIBC environement.
+ Build the collating element which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a
+ pointer argument sinse we may update it. */
+
+ auto inline reg_errcode_t
+ __attribute ((always_inline))
+ build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name)
+ re_charset_t *mbcset;
+ int *coll_sym_alloc;
+ bitset_t sbcset;
+ const unsigned char *name;
+ {
+ int32_t elem, idx;
+ size_t name_len = strlen ((const char *) name);
+ if (nrules != 0)
+ {
+ elem = seek_collating_symbol_entry (name, name_len);
+ if (symb_table[2 * elem] != 0)
+ {
+ /* We found the entry. */
+ idx = symb_table[2 * elem + 1];
+ /* Skip the name of collating element name. */
+ idx += 1 + extra[idx];
+ }
+ else if (symb_table[2 * elem] == 0 && name_len == 1)
+ {
+ /* No valid character, treat it as a normal
+ character. */
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ else
+ return REG_ECOLLATE;
+
+ /* Got valid collation sequence, add it as a new entry. */
+ /* Check the space of the arrays. */
+ if (BE (*coll_sym_alloc == mbcset->ncoll_syms, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->ncoll_syms is 0. */
+ int new_coll_sym_alloc = 2 * mbcset->ncoll_syms + 1;
+ /* Use realloc since mbcset->coll_syms is NULL
+ if *alloc == 0. */
+ int32_t *new_coll_syms = re_realloc (mbcset->coll_syms, int32_t,
+ new_coll_sym_alloc);
+ if (BE (new_coll_syms == NULL, 0))
+ return REG_ESPACE;
+ mbcset->coll_syms = new_coll_syms;
+ *coll_sym_alloc = new_coll_sym_alloc;
+ }
+ mbcset->coll_syms[mbcset->ncoll_syms++] = idx;
+ return REG_NOERROR;
+ }
+ else
+ {
+ if (BE (name_len != 1, 0))
+ return REG_ECOLLATE;
+ else
+ {
+ bitset_set (sbcset, name[0]);
+ return REG_NOERROR;
+ }
+ }
+ }
+#endif
+
+ re_token_t br_token;
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0;
+ int equiv_class_alloc = 0, char_class_alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ int non_match = 0;
+ bin_tree_t *work_tree;
+ int token_len;
+ int first_round = 1;
+#ifdef _LIBC
+ collseqmb = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules)
+ {
+ /*
+ if (MB_CUR_MAX > 1)
+ */
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB);
+ symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_TABLEMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_SYMB_EXTRAMB);
+ }
+#endif
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else
+ if (BE (sbcset == NULL, 0))
+#endif /* RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_NON_MATCH_LIST)
+ {
+#ifdef RE_ENABLE_I18N
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ non_match = 1;
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set (sbcset, '\0');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_BADPAT;
+ goto parse_bracket_exp_free_return;
+ }
+ }
+
+ /* We treat the first ']' as a normal character. */
+ if (token->type == OP_CLOSE_BRACKET)
+ token->type = CHARACTER;
+
+ while (1)
+ {
+ bracket_elem_t start_elem, end_elem;
+ unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE];
+ unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE];
+ reg_errcode_t ret;
+ int token_len2 = 0, is_range_exp = 0;
+ re_token_t token2;
+
+ start_elem.opr.name = start_name_buf;
+ ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa,
+ syntax, first_round);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+ first_round = 0;
+
+ /* Get information about the next token. We need it in any case. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+ /* Do not check for ranges if we know they are not allowed. */
+ if (start_elem.type != CHAR_CLASS && start_elem.type != EQUIV_CLASS)
+ {
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CHARSET_RANGE)
+ {
+ re_string_skip_bytes (regexp, token_len); /* Skip '-'. */
+ token_len2 = peek_token_bracket (&token2, regexp, syntax);
+ if (BE (token2.type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token2.type == OP_CLOSE_BRACKET)
+ {
+ /* We treat the last '-' as a normal character. */
+ re_string_skip_bytes (regexp, -token_len);
+ token->type = CHARACTER;
+ }
+ else
+ is_range_exp = 1;
+ }
+ }
+
+ if (is_range_exp == 1)
+ {
+ end_elem.opr.name = end_name_buf;
+ ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2,
+ dfa, syntax, 1);
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ *err = ret;
+ goto parse_bracket_exp_free_return;
+ }
+
+ token_len = peek_token_bracket (token, regexp, syntax);
+
+#ifdef _LIBC
+ *err = build_range_exp (sbcset, mbcset, &range_alloc,
+ &start_elem, &end_elem);
+#else
+# ifdef RE_ENABLE_I18N
+ *err = build_range_exp (sbcset,
+ dfa->mb_cur_max > 1 ? mbcset : NULL,
+ &range_alloc, &start_elem, &end_elem);
+# else
+ *err = build_range_exp (sbcset, &start_elem, &end_elem);
+# endif
+#endif /* RE_ENABLE_I18N */
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ }
+ else
+ {
+ switch (start_elem.type)
+ {
+ case SB_CHAR:
+ bitset_set (sbcset, start_elem.opr.ch);
+ break;
+#ifdef RE_ENABLE_I18N
+ case MB_CHAR:
+ /* Check whether the array has enough space. */
+ if (BE (mbchar_alloc == mbcset->nmbchars, 0))
+ {
+ wchar_t *new_mbchars;
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nmbchars is 0. */
+ mbchar_alloc = 2 * mbcset->nmbchars + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ new_mbchars = re_realloc (mbcset->mbchars, wchar_t,
+ mbchar_alloc);
+ if (BE (new_mbchars == NULL, 0))
+ goto parse_bracket_exp_espace;
+ mbcset->mbchars = new_mbchars;
+ }
+ mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch;
+ break;
+#endif /* RE_ENABLE_I18N */
+ case EQUIV_CLASS:
+ *err = build_equiv_class (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &equiv_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case COLL_SYM:
+ *err = build_collating_symbol (sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &coll_sym_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ case CHAR_CLASS:
+ *err = build_charclass (regexp->trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &char_class_alloc,
+#endif /* RE_ENABLE_I18N */
+ start_elem.opr.name, syntax);
+ if (BE (*err != REG_NOERROR, 0))
+ goto parse_bracket_exp_free_return;
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ }
+ if (BE (token->type == END_OF_RE, 0))
+ {
+ *err = REG_EBRACK;
+ goto parse_bracket_exp_free_return;
+ }
+ if (token->type == OP_CLOSE_BRACKET)
+ break;
+ }
+
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+
+ if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes
+ || mbcset->nranges || (dfa->mb_cur_max > 1 && (mbcset->nchar_classes
+ || mbcset->non_match)))
+ {
+ bin_tree_t *mbc_tree;
+ int sbc_idx;
+ /* Build a tree for complex bracket. */
+ dfa->has_mb_node = 1;
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ for (sbc_idx = 0; sbc_idx < BITSET_WORDS; ++sbc_idx)
+ if (sbcset[sbc_idx])
+ break;
+ /* If there are no bits set in sbcset, there is no point
+ of having both SIMPLE_BRACKET and COMPLEX_BRACKET. */
+ if (sbc_idx < BITSET_WORDS)
+ {
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+
+ /* Then join them by ALT node. */
+ work_tree = create_tree (dfa, work_tree, mbc_tree, OP_ALT);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ else
+ {
+ re_free (sbcset);
+ work_tree = mbc_tree;
+ }
+ }
+ else
+#endif /* not RE_ENABLE_I18N */
+ {
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ work_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (work_tree == NULL, 0))
+ goto parse_bracket_exp_espace;
+ }
+ return work_tree;
+
+ parse_bracket_exp_espace:
+ *err = REG_ESPACE;
+ parse_bracket_exp_free_return:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ return NULL;
+}
+
+/* Parse an element in the bracket expression. */
+
+static reg_errcode_t
+parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token, int token_len, re_dfa_t *dfa,
+ reg_syntax_t syntax, int accept_hyphen)
+{
+#ifdef RE_ENABLE_I18N
+ int cur_char_size;
+ cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp));
+ if (cur_char_size > 1)
+ {
+ elem->type = MB_CHAR;
+ elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp));
+ re_string_skip_bytes (regexp, cur_char_size);
+ return REG_NOERROR;
+ }
+#endif /* RE_ENABLE_I18N */
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS
+ || token->type == OP_OPEN_EQUIV_CLASS)
+ return parse_bracket_symbol (elem, regexp, token);
+ if (BE (token->type == OP_CHARSET_RANGE, 0) && !accept_hyphen)
+ {
+ /* A '-' must only appear as anything but a range indicator before
+ the closing bracket. Everything else is an error. */
+ re_token_t token2;
+ (void) peek_token_bracket (&token2, regexp, syntax);
+ if (token2.type != OP_CLOSE_BRACKET)
+ /* The actual error value is not standardized since this whole
+ case is undefined. But ERANGE makes good sense. */
+ return REG_ERANGE;
+ }
+ elem->type = SB_CHAR;
+ elem->opr.ch = token->opr.c;
+ return REG_NOERROR;
+}
+
+/* Parse a bracket symbol in the bracket expression. Bracket symbols are
+ such as [:<character_class>:], [.<collating_element>.], and
+ [=<equivalent_class>=]. */
+
+static reg_errcode_t
+parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp,
+ re_token_t *token)
+{
+ unsigned char ch, delim = token->opr.c;
+ int i = 0;
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ for (;; ++i)
+ {
+ if (i >= BRACKET_NAME_BUF_SIZE)
+ return REG_EBRACK;
+ if (token->type == OP_OPEN_CHAR_CLASS)
+ ch = re_string_fetch_byte_case (regexp);
+ else
+ ch = re_string_fetch_byte (regexp);
+ if (re_string_eoi(regexp))
+ return REG_EBRACK;
+ if (ch == delim && re_string_peek_byte (regexp, 0) == ']')
+ break;
+ elem->opr.name[i] = ch;
+ }
+ re_string_skip_bytes (regexp, 1);
+ elem->opr.name[i] = '\0';
+ switch (token->type)
+ {
+ case OP_OPEN_COLL_ELEM:
+ elem->type = COLL_SYM;
+ break;
+ case OP_OPEN_EQUIV_CLASS:
+ elem->type = EQUIV_CLASS;
+ break;
+ case OP_OPEN_CHAR_CLASS:
+ elem->type = CHAR_CLASS;
+ break;
+ default:
+ break;
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the equivalence class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_equiv_class (bitset_t sbcset, re_charset_t *mbcset,
+ int *equiv_class_alloc, const unsigned char *name)
+#else /* not RE_ENABLE_I18N */
+build_equiv_class (bitset_t sbcset, const unsigned char *name)
+#endif /* not RE_ENABLE_I18N */
+{
+#ifdef _LIBC
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra, *cp;
+ unsigned char char_buf[2];
+ int32_t idx1, idx2;
+ unsigned int ch;
+ size_t len;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+ /* Calculate the index for equivalence class. */
+ cp = name;
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ idx1 = findidx (&cp);
+ if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0))
+ /* This isn't a valid character. */
+ return REG_ECOLLATE;
+
+ /* Build single byte matcing table for this equivalence class. */
+ char_buf[1] = (unsigned char) '\0';
+ len = weights[idx1];
+ for (ch = 0; ch < SBC_MAX; ++ch)
+ {
+ char_buf[0] = ch;
+ cp = char_buf;
+ idx2 = findidx (&cp);
+/*
+ idx2 = table[ch];
+*/
+ if (idx2 == 0)
+ /* This isn't a valid character. */
+ continue;
+ if (len == weights[idx2])
+ {
+ int cnt = 0;
+ while (cnt <= len &&
+ weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt])
+ ++cnt;
+
+ if (cnt > len)
+ bitset_set (sbcset, ch);
+ }
+ }
+ /* Check whether the array has enough space. */
+ if (BE (*equiv_class_alloc == mbcset->nequiv_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nequiv_classes is 0. */
+ int new_equiv_class_alloc = 2 * mbcset->nequiv_classes + 1;
+ /* Use realloc since the array is NULL if *alloc == 0. */
+ int32_t *new_equiv_classes = re_realloc (mbcset->equiv_classes,
+ int32_t,
+ new_equiv_class_alloc);
+ if (BE (new_equiv_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->equiv_classes = new_equiv_classes;
+ *equiv_class_alloc = new_equiv_class_alloc;
+ }
+ mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1;
+ }
+ else
+#endif /* _LIBC */
+ {
+ if (BE (strlen ((const char *) name) != 1, 0))
+ return REG_ECOLLATE;
+ bitset_set (sbcset, *name);
+ }
+ return REG_NOERROR;
+}
+
+ /* Helper function for parse_bracket_exp.
+ Build the character class which is represented by NAME.
+ The result are written to MBCSET and SBCSET.
+ CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
+ is a pointer argument sinse we may update it. */
+
+static reg_errcode_t
+#ifdef RE_ENABLE_I18N
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ re_charset_t *mbcset, int *char_class_alloc,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#else /* not RE_ENABLE_I18N */
+build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
+ const unsigned char *class_name, reg_syntax_t syntax)
+#endif /* not RE_ENABLE_I18N */
+{
+ int i;
+ const char *name = (const char *) class_name;
+
+ /* In case of REG_ICASE "upper" and "lower" match the both of
+ upper and lower cases. */
+ if ((syntax & RE_ICASE)
+ && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
+ name = "alpha";
+
+#ifdef RE_ENABLE_I18N
+ /* Check the space of the arrays. */
+ if (BE (*char_class_alloc == mbcset->nchar_classes, 0))
+ {
+ /* Not enough, realloc it. */
+ /* +1 in case of mbcset->nchar_classes is 0. */
+ int new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
+ /* Use realloc since array is NULL if *alloc == 0. */
+ wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
+ new_char_class_alloc);
+ if (BE (new_char_classes == NULL, 0))
+ return REG_ESPACE;
+ mbcset->char_classes = new_char_classes;
+ *char_class_alloc = new_char_class_alloc;
+ }
+ mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
+#endif /* RE_ENABLE_I18N */
+
+#define BUILD_CHARCLASS_LOOP(ctype_func) \
+ do { \
+ if (BE (trans != NULL, 0)) \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, trans[i]); \
+ } \
+ else \
+ { \
+ for (i = 0; i < SBC_MAX; ++i) \
+ if (ctype_func (i)) \
+ bitset_set (sbcset, i); \
+ } \
+ } while (0)
+
+ if (strcmp (name, "alnum") == 0)
+ BUILD_CHARCLASS_LOOP (isalnum);
+ else if (strcmp (name, "cntrl") == 0)
+ BUILD_CHARCLASS_LOOP (iscntrl);
+ else if (strcmp (name, "lower") == 0)
+ BUILD_CHARCLASS_LOOP (islower);
+ else if (strcmp (name, "space") == 0)
+ BUILD_CHARCLASS_LOOP (isspace);
+ else if (strcmp (name, "alpha") == 0)
+ BUILD_CHARCLASS_LOOP (isalpha);
+ else if (strcmp (name, "digit") == 0)
+ BUILD_CHARCLASS_LOOP (isdigit);
+ else if (strcmp (name, "print") == 0)
+ BUILD_CHARCLASS_LOOP (isprint);
+ else if (strcmp (name, "upper") == 0)
+ BUILD_CHARCLASS_LOOP (isupper);
+ else if (strcmp (name, "blank") == 0)
+ BUILD_CHARCLASS_LOOP (isblank);
+ else if (strcmp (name, "graph") == 0)
+ BUILD_CHARCLASS_LOOP (isgraph);
+ else if (strcmp (name, "punct") == 0)
+ BUILD_CHARCLASS_LOOP (ispunct);
+ else if (strcmp (name, "xdigit") == 0)
+ BUILD_CHARCLASS_LOOP (isxdigit);
+ else
+ return REG_ECTYPE;
+
+ return REG_NOERROR;
+}
+
+static bin_tree_t *
+build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
+ const unsigned char *class_name,
+ const unsigned char *extra, int non_match,
+ reg_errcode_t *err)
+{
+ re_bitset_ptr_t sbcset;
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset;
+ int alloc = 0;
+#endif /* not RE_ENABLE_I18N */
+ reg_errcode_t ret;
+ re_token_t br_token;
+ bin_tree_t *tree;
+
+ sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1);
+#ifdef RE_ENABLE_I18N
+ mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1);
+#endif /* RE_ENABLE_I18N */
+
+#ifdef RE_ENABLE_I18N
+ if (BE (sbcset == NULL || mbcset == NULL, 0))
+#else /* not RE_ENABLE_I18N */
+ if (BE (sbcset == NULL, 0))
+#endif /* not RE_ENABLE_I18N */
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ if (non_match)
+ {
+#ifdef RE_ENABLE_I18N
+ /*
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+ bitset_set(cset->sbcset, '\0');
+ */
+ mbcset->non_match = 1;
+#endif /* not RE_ENABLE_I18N */
+ }
+
+ /* We don't care the syntax in this case. */
+ ret = build_charclass (trans, sbcset,
+#ifdef RE_ENABLE_I18N
+ mbcset, &alloc,
+#endif /* RE_ENABLE_I18N */
+ class_name, 0);
+
+ if (BE (ret != REG_NOERROR, 0))
+ {
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = ret;
+ return NULL;
+ }
+ /* \w match '_' also. */
+ for (; *extra; extra++)
+ bitset_set (sbcset, *extra);
+
+ /* If it is non-matching list. */
+ if (non_match)
+ bitset_not (sbcset);
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure only single byte characters are set. */
+ if (dfa->mb_cur_max > 1)
+ bitset_mask (sbcset, dfa->sb_char);
+#endif
+
+ /* Build a tree for simple bracket. */
+ br_token.type = SIMPLE_BRACKET;
+ br_token.opr.sbcset = sbcset;
+ tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (tree == NULL, 0))
+ goto build_word_op_espace;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ bin_tree_t *mbc_tree;
+ /* Build a tree for complex bracket. */
+ br_token.type = COMPLEX_BRACKET;
+ br_token.opr.mbcset = mbcset;
+ dfa->has_mb_node = 1;
+ mbc_tree = create_token_tree (dfa, NULL, NULL, &br_token);
+ if (BE (mbc_tree == NULL, 0))
+ goto build_word_op_espace;
+ /* Then join them by ALT node. */
+ tree = create_tree (dfa, tree, mbc_tree, OP_ALT);
+ if (BE (mbc_tree != NULL, 1))
+ return tree;
+ }
+ else
+ {
+ free_charset (mbcset);
+ return tree;
+ }
+#else /* not RE_ENABLE_I18N */
+ return tree;
+#endif /* not RE_ENABLE_I18N */
+
+ build_word_op_espace:
+ re_free (sbcset);
+#ifdef RE_ENABLE_I18N
+ free_charset (mbcset);
+#endif /* RE_ENABLE_I18N */
+ *err = REG_ESPACE;
+ return NULL;
+}
+
+/* This is intended for the expressions like "a{1,3}".
+ Fetch a number from `input', and return the number.
+ Return -1, if the number field is empty like "{,1}".
+ Return -2, If an error is occured. */
+
+static int
+fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
+{
+ int num = -1;
+ unsigned char c;
+ while (1)
+ {
+ fetch_token (token, input, syntax);
+ c = token->opr.c;
+ if (BE (token->type == END_OF_RE, 0))
+ return -2;
+ if (token->type == OP_CLOSE_DUP_NUM || c == ',')
+ break;
+ num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2)
+ ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0'));
+ num = (num > RE_DUP_MAX) ? -2 : num;
+ }
+ return num;
+}
+
+#ifdef RE_ENABLE_I18N
+static void
+free_charset (re_charset_t *cset)
+{
+ re_free (cset->mbchars);
+# ifdef _LIBC
+ re_free (cset->coll_syms);
+ re_free (cset->equiv_classes);
+ re_free (cset->range_starts);
+ re_free (cset->range_ends);
+# endif
+ re_free (cset->char_classes);
+ re_free (cset);
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Functions for binary tree operation. */
+
+/* Create a tree node. */
+
+static bin_tree_t *
+create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ re_token_type_t type)
+{
+ re_token_t t;
+ t.type = type;
+ return create_token_tree (dfa, left, right, &t);
+}
+
+static bin_tree_t *
+create_token_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right,
+ const re_token_t *token)
+{
+ bin_tree_t *tree;
+ if (BE (dfa->str_tree_storage_idx == BIN_TREE_STORAGE_SIZE, 0))
+ {
+ bin_tree_storage_t *storage = re_malloc (bin_tree_storage_t, 1);
+
+ if (storage == NULL)
+ return NULL;
+ storage->next = dfa->str_tree_storage;
+ dfa->str_tree_storage = storage;
+ dfa->str_tree_storage_idx = 0;
+ }
+ tree = &dfa->str_tree_storage->data[dfa->str_tree_storage_idx++];
+
+ tree->parent = NULL;
+ tree->left = left;
+ tree->right = right;
+ tree->token = *token;
+ tree->token.duplicated = 0;
+ tree->token.opt_subexp = 0;
+ tree->first = NULL;
+ tree->next = NULL;
+ tree->node_idx = -1;
+
+ if (left != NULL)
+ left->parent = tree;
+ if (right != NULL)
+ right->parent = tree;
+ return tree;
+}
+
+/* Mark the tree SRC as an optional subexpression.
+ To be called from preorder or postorder. */
+
+static reg_errcode_t
+mark_opt_subexp (void *extra, bin_tree_t *node)
+{
+ int idx = (int) (long) extra;
+ if (node->token.type == SUBEXP && node->token.opr.idx == idx)
+ node->token.opt_subexp = 1;
+
+ return REG_NOERROR;
+}
+
+/* Free the allocated memory inside NODE. */
+
+static void
+free_token (re_token_t *node)
+{
+#ifdef RE_ENABLE_I18N
+ if (node->type == COMPLEX_BRACKET && node->duplicated == 0)
+ free_charset (node->opr.mbcset);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (node->type == SIMPLE_BRACKET && node->duplicated == 0)
+ re_free (node->opr.sbcset);
+}
+
+/* Worker function for tree walking. Free the allocated memory inside NODE
+ and its children. */
+
+static reg_errcode_t
+free_tree (void *extra, bin_tree_t *node)
+{
+ free_token (&node->token);
+ return REG_NOERROR;
+}
+
+
+/* Duplicate the node SRC, and return new node. This is a preorder
+ visit similar to the one implemented by the generic visitor, but
+ we need more infrastructure to maintain two parallel trees --- so,
+ it's easier to duplicate. */
+
+static bin_tree_t *
+duplicate_tree (const bin_tree_t *root, re_dfa_t *dfa)
+{
+ const bin_tree_t *node;
+ bin_tree_t *dup_root;
+ bin_tree_t **p_new = &dup_root, *dup_node = root->parent;
+
+ for (node = root; ; )
+ {
+ /* Create a new tree and link it back to the current parent. */
+ *p_new = create_token_tree (dfa, NULL, NULL, &node->token);
+ if (*p_new == NULL)
+ return NULL;
+ (*p_new)->parent = dup_node;
+ (*p_new)->token.duplicated = 1;
+ dup_node = *p_new;
+
+ /* Go to the left node, or up and to the right. */
+ if (node->left)
+ {
+ node = node->left;
+ p_new = &dup_node->left;
+ }
+ else
+ {
+ const bin_tree_t *prev = NULL;
+ while (node->right == prev || node->right == NULL)
+ {
+ prev = node;
+ node = node->parent;
+ dup_node = dup_node->parent;
+ if (!node)
+ return dup_root;
+ }
+ node = node->right;
+ p_new = &dup_node->right;
+ }
+ }
+}
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.c b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.c
new file mode 100644
index 0000000..d2d4f28
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.c
@@ -0,0 +1,74 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Make sure noone compiles this code with a C++ compiler. */
+#ifdef __cplusplus
+# error "This is C code, use a C compiler"
+#endif
+
+#ifdef _LIBC
+/* We have to keep the namespace clean. */
+# define regfree(preg) __regfree (preg)
+# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef)
+# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags)
+# define regerror(errcode, preg, errbuf, errbuf_size) \
+ __regerror(errcode, preg, errbuf, errbuf_size)
+# define re_set_registers(bu, re, nu, st, en) \
+ __re_set_registers (bu, re, nu, st, en)
+# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \
+ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+# define re_match(bufp, string, size, pos, regs) \
+ __re_match (bufp, string, size, pos, regs)
+# define re_search(bufp, string, size, startpos, range, regs) \
+ __re_search (bufp, string, size, startpos, range, regs)
+# define re_compile_pattern(pattern, length, bufp) \
+ __re_compile_pattern (pattern, length, bufp)
+# define re_set_syntax(syntax) __re_set_syntax (syntax)
+# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \
+ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop)
+# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp)
+
+# include "../locale/localeinfo.h"
+#endif
+
+/* On some systems, limits.h sets RE_DUP_MAX to a lower value than
+ GNU regex allows. Include it before <regex.h>, which correctly
+ #undefs RE_DUP_MAX and sets it to the right value. */
+#include <limits.h>
+
+#include <regex.h>
+#include "regex_internal.h"
+
+#include "regex_internal.c"
+#include "regcomp.c"
+#include "regexec.c"
+
+/* Binary backward compatibility. */
+#if _LIBC
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3)
+link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.")
+int re_max_failures = 2000;
+# endif
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.h b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.h
new file mode 100644
index 0000000..807c404
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex.h
@@ -0,0 +1,556 @@
+/* Definitions for data structures and routines for the regular
+ expression library.
+ Copyright (C) 1985,1989-93,1995-98,2000,2001,2002,2003,2005,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_H
+#define _REGEX_H 1
+
+#include <sys/types.h>
+
+/* Allow the use in C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following two types have to be signed and unsigned integer type
+ wide enough to hold a value of a pointer. For most ANSI compilers
+ ptrdiff_t and size_t should be likely OK. Still size of these two
+ types is 2 for Microsoft C. Ugh... */
+typedef long int s_reg_t;
+typedef unsigned long int active_reg_t;
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned long int reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+
+/* This bit is used internally like RE_CONTEXT_INDEP_ANCHORS but only
+ for ^, because it is difficult to scan the regex backwards to find
+ whether ^ should be special. */
+#define RE_CARET_ANCHORS_HERE (RE_ICASE << 1)
+
+/* If this bit is set, then \{ cannot be first in an bre or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_DUP (RE_CARET_ANCHORS_HERE << 1)
+
+/* If this bit is set, then no_sub will be set to 1 during
+ re_compile_pattern. */
+#define RE_NO_SUB (RE_CONTEXT_INVALID_DUP << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GNU_AWK \
+ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
+ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \
+ | RE_CONTEXT_INVALID_OPS ))
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
+ | RE_INTERVALS | RE_NO_GNU_OPS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \
+ | RE_INVALID_INTERVAL_ORD)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_CONTEXT_INVALID_DUP)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is
+ removed and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+# undef RE_DUP_MAX
+#endif
+/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
+#define RE_DUP_MAX (0x7fff)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+/* Use PMATCH[0] to delimit the start and end of the search in the
+ buffer. */
+#define REG_STARTEND (1 << 2)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+#ifdef _XOPEN_SOURCE
+ REG_ENOSYS = -1, /* This will never happen for this implementation. */
+#endif
+
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Inalid collating element. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+#ifndef RE_TRANSLATE_TYPE
+# define RE_TRANSLATE_TYPE unsigned char *
+#endif
+
+struct re_pattern_buffer
+{
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are sometimes used as
+ array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long int allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long int used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses the
+ fastmap, if there is one, to skip over impossible starting points
+ for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation is
+ applied to a pattern when it is compiled and to a string when it
+ is matched. */
+ RE_TRANSLATE_TYPE translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see whether or
+ not we should use the fastmap, so we don't set this absolutely
+ perfectly; see `re_compile_fastmap' (the `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the beginning
+ of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+# define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax (reg_syntax_t __syntax);
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern (const char *__pattern, size_t __length,
+ struct re_pattern_buffer *__buffer);
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap (struct re_pattern_buffer *__buffer);
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search (struct re_pattern_buffer *__buffer, const char *__string,
+ int __length, int __start, int __range,
+ struct re_registers *__regs);
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, int __length1,
+ const char *__string2, int __length2, int __start,
+ int __range, struct re_registers *__regs, int __stop);
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match (struct re_pattern_buffer *__buffer, const char *__string,
+ int __length, int __start, struct re_registers *__regs);
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2 (struct re_pattern_buffer *__buffer,
+ const char *__string1, int __length1,
+ const char *__string2, int __length2, int __start,
+ struct re_registers *__regs, int __stop);
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers (struct re_pattern_buffer *__buffer,
+ struct re_registers *__regs,
+ unsigned int __num_regs,
+ regoff_t *__starts, regoff_t *__ends);
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+# ifndef _CRAY
+/* 4.2 bsd compatibility. */
+extern char *re_comp (const char *);
+extern int re_exec (const char *);
+# endif
+#endif
+
+/* GCC 2.95 and later have "__restrict"; C99 compilers have
+ "restrict", and "configure" may have defined "restrict". */
+#ifndef __restrict
+# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__))
+# if defined restrict || 199901L <= __STDC_VERSION__
+# define __restrict restrict
+# else
+# define __restrict
+# endif
+# endif
+#endif
+/* gcc 3.1 and up support the [restrict] syntax. */
+#ifndef __restrict_arr
+# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
+ && !defined __GNUG__
+# define __restrict_arr __restrict
+# else
+# define __restrict_arr
+# endif
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp (regex_t *__restrict __preg,
+ const char *__restrict __pattern,
+ int __cflags);
+
+extern int regexec (const regex_t *__restrict __preg,
+ const char *__restrict __string, size_t __nmatch,
+ regmatch_t __pmatch[__restrict_arr],
+ int __eflags);
+
+extern size_t regerror (int __errcode, const regex_t *__restrict __preg,
+ char *__restrict __errbuf, size_t __errbuf_size);
+
+extern void regfree (regex_t *__preg);
+
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* regex.h */
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.c b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.c
new file mode 100644
index 0000000..66154e0
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.c
@@ -0,0 +1,1717 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static void re_string_construct_common (const char *str, int len,
+ re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa) internal_function;
+static re_dfastate_t *create_ci_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int hash) internal_function;
+static re_dfastate_t *create_cd_newstate (const re_dfa_t *dfa,
+ const re_node_set *nodes,
+ unsigned int context,
+ unsigned int hash) internal_function;
+
+/* Functions for string operation. */
+
+/* This function allocate the buffers. It is necessary to call
+ re_string_reconstruct before using the object. */
+
+static reg_errcode_t
+internal_function
+re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ int init_buf_len;
+
+ /* Ensure at least one character fits into the buffers. */
+ if (init_len < dfa->mb_cur_max)
+ init_len = dfa->mb_cur_max;
+ init_buf_len = (len + 1 < init_len) ? len + 1: init_len;
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ ret = re_string_realloc_buffers (pstr, init_buf_len);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ pstr->word_char = dfa->word_char;
+ pstr->word_ops_used = dfa->word_ops_used;
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+ pstr->valid_len = (pstr->mbs_allocated || dfa->mb_cur_max > 1) ? 0 : len;
+ pstr->valid_raw_len = pstr->valid_len;
+ return REG_NOERROR;
+}
+
+/* This function allocate the buffers, and initialize them. */
+
+static reg_errcode_t
+internal_function
+re_string_construct (re_string_t *pstr, const char *str, int len,
+ RE_TRANSLATE_TYPE trans, int icase, const re_dfa_t *dfa)
+{
+ reg_errcode_t ret;
+ memset (pstr, '\0', sizeof (re_string_t));
+ re_string_construct_common (str, len, pstr, trans, icase, dfa);
+
+ if (len > 0)
+ {
+ ret = re_string_realloc_buffers (pstr, len + 1);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ pstr->mbs = pstr->mbs_allocated ? pstr->mbs : (unsigned char *) str;
+
+ if (icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ {
+ while (1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ if (pstr->valid_raw_len >= len)
+ break;
+ if (pstr->bufs_len > pstr->valid_len + dfa->mb_cur_max)
+ break;
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (trans != NULL)
+ re_string_translate_buffer (pstr);
+ else
+ {
+ pstr->valid_len = pstr->bufs_len;
+ pstr->valid_raw_len = pstr->bufs_len;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions for re_string_allocate, and re_string_construct. */
+
+static reg_errcode_t
+internal_function
+re_string_realloc_buffers (re_string_t *pstr, int new_buf_len)
+{
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ wint_t *new_wcs = re_realloc (pstr->wcs, wint_t, new_buf_len);
+ if (BE (new_wcs == NULL, 0))
+ return REG_ESPACE;
+ pstr->wcs = new_wcs;
+ if (pstr->offsets != NULL)
+ {
+ int *new_offsets = re_realloc (pstr->offsets, int, new_buf_len);
+ if (BE (new_offsets == NULL, 0))
+ return REG_ESPACE;
+ pstr->offsets = new_offsets;
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ {
+ unsigned char *new_mbs = re_realloc (pstr->mbs, unsigned char,
+ new_buf_len);
+ if (BE (new_mbs == NULL, 0))
+ return REG_ESPACE;
+ pstr->mbs = new_mbs;
+ }
+ pstr->bufs_len = new_buf_len;
+ return REG_NOERROR;
+}
+
+
+static void
+internal_function
+re_string_construct_common (const char *str, int len, re_string_t *pstr,
+ RE_TRANSLATE_TYPE trans, int icase,
+ const re_dfa_t *dfa)
+{
+ pstr->raw_mbs = (const unsigned char *) str;
+ pstr->len = len;
+ pstr->raw_len = len;
+ pstr->trans = trans;
+ pstr->icase = icase ? 1 : 0;
+ pstr->mbs_allocated = (trans != NULL || icase);
+ pstr->mb_cur_max = dfa->mb_cur_max;
+ pstr->is_utf8 = dfa->is_utf8;
+ pstr->map_notascii = dfa->map_notascii;
+ pstr->stop = pstr->len;
+ pstr->raw_stop = pstr->stop;
+}
+
+#ifdef RE_ENABLE_I18N
+
+/* Build wide character buffer PSTR->WCS.
+ If the byte sequence of the string are:
+ <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3>
+ Then wide character buffer will be:
+ <wc1> , WEOF , <wc2> , WEOF , <wc3>
+ We use WEOF for padding, they indicate that the position isn't
+ a first byte of a multibyte character.
+
+ Note that this function assumes PSTR->VALID_LEN elements are already
+ built and starts from PSTR->VALID_LEN. */
+
+static void
+internal_function
+build_wcs_buffer (re_string_t *pstr)
+{
+#ifdef _LIBC
+ unsigned char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ unsigned char buf[64];
+#endif
+ mbstate_t prev_st;
+ int byte_idx, end_idx, remain_len;
+ size_t mbclen;
+
+ /* Build the buffers from pstr->valid_len to either pstr->len or
+ pstr->bufs_len. */
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+ for (byte_idx = pstr->valid_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ /* Apply the translation if we need. */
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + byte_idx + i];
+ buf[i] = pstr->mbs[byte_idx + i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a singlebyte character. */
+ mbclen = 1;
+ wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ if (BE (pstr->trans != NULL, 0))
+ wc = pstr->trans[wc];
+ pstr->cur_state = prev_st;
+ }
+
+ /* Write wide character and padding. */
+ pstr->wcs[byte_idx++] = wc;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+}
+
+/* Build wide character buffer PSTR->WCS like build_wcs_buffer,
+ but for REG_ICASE. */
+
+static reg_errcode_t
+internal_function
+build_wcs_upper_buffer (re_string_t *pstr)
+{
+ mbstate_t prev_st;
+ int src_idx, byte_idx, end_idx, remain_len;
+ size_t mbclen;
+#ifdef _LIBC
+ char buf[MB_LEN_MAX];
+ assert (MB_LEN_MAX >= pstr->mb_cur_max);
+#else
+ char buf[64];
+#endif
+
+ byte_idx = pstr->valid_len;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ /* The following optimization assumes that ASCII characters can be
+ mapped to wide characters with a simple cast. */
+ if (! pstr->map_notascii && pstr->trans == NULL && !pstr->offsets_needed)
+ {
+ while (byte_idx < end_idx)
+ {
+ wchar_t wc;
+
+ if (isascii (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx])
+ && mbsinit (&pstr->cur_state))
+ {
+ /* In case of a singlebyte character. */
+ pstr->mbs[byte_idx]
+ = toupper (pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]);
+ /* The next step uses the assumption that wchar_t is encoded
+ ASCII-safe: all ASCII values can be converted like this. */
+ pstr->wcs[byte_idx] = (wchar_t) pstr->mbs[byte_idx];
+ ++byte_idx;
+ continue;
+ }
+
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc,
+ ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
+ + byte_idx), remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb (buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else
+ {
+ src_idx = byte_idx;
+ goto offsets_needed;
+ }
+ }
+ else
+ memcpy (pstr->mbs + byte_idx,
+ pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen);
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
+ pstr->mbs[byte_idx] = ch;
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = byte_idx;
+ return REG_NOERROR;
+ }
+ else
+ for (src_idx = pstr->valid_raw_len; byte_idx < end_idx;)
+ {
+ wchar_t wc;
+ const char *p;
+ offsets_needed:
+ remain_len = end_idx - byte_idx;
+ prev_st = pstr->cur_state;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i, ch;
+
+ for (i = 0; i < pstr->mb_cur_max && i < remain_len; ++i)
+ {
+ ch = pstr->raw_mbs [pstr->raw_mbs_idx + src_idx + i];
+ buf[i] = pstr->trans[ch];
+ }
+ p = (const char *) buf;
+ }
+ else
+ p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
+ mbclen = mbrtowc (&wc, p, remain_len, &pstr->cur_state);
+ if (BE (mbclen + 2 > 2, 1))
+ {
+ wchar_t wcu = wc;
+ if (iswlower (wc))
+ {
+ size_t mbcdlen;
+
+ wcu = towupper (wc);
+ mbcdlen = wcrtomb ((char *) buf, wcu, &prev_st);
+ if (BE (mbclen == mbcdlen, 1))
+ memcpy (pstr->mbs + byte_idx, buf, mbclen);
+ else if (mbcdlen != (size_t) -1)
+ {
+ size_t i;
+
+ if (byte_idx + mbcdlen > pstr->bufs_len)
+ {
+ pstr->cur_state = prev_st;
+ break;
+ }
+
+ if (pstr->offsets == NULL)
+ {
+ pstr->offsets = re_malloc (int, pstr->bufs_len);
+
+ if (pstr->offsets == NULL)
+ return REG_ESPACE;
+ }
+ if (!pstr->offsets_needed)
+ {
+ for (i = 0; i < (size_t) byte_idx; ++i)
+ pstr->offsets[i] = i;
+ pstr->offsets_needed = 1;
+ }
+
+ memcpy (pstr->mbs + byte_idx, buf, mbcdlen);
+ pstr->wcs[byte_idx] = wcu;
+ pstr->offsets[byte_idx] = src_idx;
+ for (i = 1; i < mbcdlen; ++i)
+ {
+ pstr->offsets[byte_idx + i]
+ = src_idx + (i < mbclen ? i : mbclen - 1);
+ pstr->wcs[byte_idx + i] = WEOF;
+ }
+ pstr->len += mbcdlen - mbclen;
+ if (pstr->raw_stop > src_idx)
+ pstr->stop += mbcdlen - mbclen;
+ end_idx = (pstr->bufs_len > pstr->len)
+ ? pstr->len : pstr->bufs_len;
+ byte_idx += mbcdlen;
+ src_idx += mbclen;
+ continue;
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+ }
+ else
+ memcpy (pstr->mbs + byte_idx, p, mbclen);
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ {
+ size_t i;
+ for (i = 0; i < mbclen; ++i)
+ pstr->offsets[byte_idx + i] = src_idx + i;
+ }
+ src_idx += mbclen;
+
+ pstr->wcs[byte_idx++] = wcu;
+ /* Write paddings. */
+ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
+ pstr->wcs[byte_idx++] = WEOF;
+ }
+ else if (mbclen == (size_t) -1 || mbclen == 0)
+ {
+ /* It is an invalid character or '\0'. Just use the byte. */
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
+
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans [ch];
+ pstr->mbs[byte_idx] = ch;
+
+ if (BE (pstr->offsets_needed != 0, 0))
+ pstr->offsets[byte_idx] = src_idx;
+ ++src_idx;
+
+ /* And also cast it to wide char. */
+ pstr->wcs[byte_idx++] = (wchar_t) ch;
+ if (BE (mbclen == (size_t) -1, 0))
+ pstr->cur_state = prev_st;
+ }
+ else
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
+ }
+ pstr->valid_len = byte_idx;
+ pstr->valid_raw_len = src_idx;
+ return REG_NOERROR;
+}
+
+/* Skip characters until the index becomes greater than NEW_RAW_IDX.
+ Return the index. */
+
+static int
+internal_function
+re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc)
+{
+ mbstate_t prev_st;
+ int rawbuf_idx;
+ size_t mbclen;
+ wchar_t wc = WEOF;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+ rawbuf_idx < new_raw_idx;)
+ {
+ int remain_len;
+ remain_len = pstr->len - rawbuf_idx;
+ prev_st = pstr->cur_state;
+ mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+ /* We treat these cases as a single byte character. */
+ if (mbclen == 0 || remain_len == 0)
+ wc = L'\0';
+ else
+ wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+ /* Then proceed the next character. */
+ rawbuf_idx += mbclen;
+ }
+ *last_wc = (wint_t) wc;
+ return rawbuf_idx;
+}
+#endif /* RE_ENABLE_I18N */
+
+/* Build the buffer PSTR->MBS, and apply the translation if we need.
+ This function is used in case of REG_ICASE. */
+
+static void
+internal_function
+build_upper_buffer (re_string_t *pstr)
+{
+ int char_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx];
+ if (BE (pstr->trans != NULL, 0))
+ ch = pstr->trans[ch];
+ if (islower (ch))
+ pstr->mbs[char_idx] = toupper (ch);
+ else
+ pstr->mbs[char_idx] = ch;
+ }
+ pstr->valid_len = char_idx;
+ pstr->valid_raw_len = char_idx;
+}
+
+/* Apply TRANS to the buffer in PSTR. */
+
+static void
+internal_function
+re_string_translate_buffer (re_string_t *pstr)
+{
+ int buf_idx, end_idx;
+ end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len;
+
+ for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx)
+ {
+ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx];
+ pstr->mbs[buf_idx] = pstr->trans[ch];
+ }
+
+ pstr->valid_len = buf_idx;
+ pstr->valid_raw_len = buf_idx;
+}
+
+/* This function re-construct the buffers.
+ Concretely, convert to wide character in case of pstr->mb_cur_max > 1,
+ convert to upper case in case of REG_ICASE, apply translation. */
+
+static reg_errcode_t
+internal_function
+re_string_reconstruct (re_string_t *pstr, int idx, int eflags)
+{
+ int offset = idx - pstr->raw_mbs_idx;
+ if (BE (offset < 0, 0))
+ {
+ /* Reset buffer. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+#endif /* RE_ENABLE_I18N */
+ pstr->len = pstr->raw_len;
+ pstr->stop = pstr->raw_stop;
+ pstr->valid_len = 0;
+ pstr->raw_mbs_idx = 0;
+ pstr->valid_raw_len = 0;
+ pstr->offsets_needed = 0;
+ pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF);
+ if (!pstr->mbs_allocated)
+ pstr->mbs = (unsigned char *) pstr->raw_mbs;
+ offset = idx;
+ }
+
+ if (BE (offset != 0, 1))
+ {
+ /* Should the already checked characters be kept? */
+ if (BE (offset < pstr->valid_raw_len, 1))
+ {
+ /* Yes, move them to the front of the buffer. */
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ int low = 0, high = pstr->valid_len, mid;
+ do
+ {
+ mid = (high + low) / 2;
+ if (pstr->offsets[mid] > offset)
+ high = mid;
+ else if (pstr->offsets[mid] < offset)
+ low = mid + 1;
+ else
+ break;
+ }
+ while (low < high);
+ if (pstr->offsets[mid] < offset)
+ ++mid;
+ pstr->tip_context = re_string_context_at (pstr, mid - 1,
+ eflags);
+ /* This can be quite complicated, so handle specially
+ only the common and easy case where the character with
+ different length representation of lower and upper
+ case is present at or after offset. */
+ if (pstr->valid_len > offset
+ && mid == offset && pstr->offsets[mid] == offset)
+ {
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+ memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+ for (low = 0; low < pstr->valid_len; low++)
+ pstr->offsets[low] = pstr->offsets[low + offset] - offset;
+ }
+ else
+ {
+ /* Otherwise, just find out how long the partial multibyte
+ character at offset is and fill it with WEOF/255. */
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ while (mid > 0 && pstr->offsets[mid - 1] == offset)
+ --mid;
+ while (mid < pstr->valid_len)
+ if (pstr->wcs[mid] != WEOF)
+ break;
+ else
+ ++mid;
+ if (mid == pstr->valid_len)
+ pstr->valid_len = 0;
+ else
+ {
+ pstr->valid_len = pstr->offsets[mid] - offset;
+ if (pstr->valid_len)
+ {
+ for (low = 0; low < pstr->valid_len; ++low)
+ pstr->wcs[low] = WEOF;
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ }
+ }
+ else
+#endif
+ {
+ pstr->tip_context = re_string_context_at (pstr, offset - 1,
+ eflags);
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ memmove (pstr->wcs, pstr->wcs + offset,
+ (pstr->valid_len - offset) * sizeof (wint_t));
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ memmove (pstr->mbs, pstr->mbs + offset,
+ pstr->valid_len - offset);
+ pstr->valid_len -= offset;
+ pstr->valid_raw_len -= offset;
+#if DEBUG
+ assert (pstr->valid_len > 0);
+#endif
+ }
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
+ int prev_valid_len = pstr->valid_len;
+
+#ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+ pstr->len = pstr->raw_len - idx + offset;
+ pstr->stop = pstr->raw_stop - idx + offset;
+ pstr->offsets_needed = 0;
+ }
+#endif
+ pstr->valid_len = 0;
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ int wcs_idx;
+ wint_t wc = WEOF;
+
+ if (pstr->is_utf8)
+ {
+ const unsigned char *raw, *p, *q, *end;
+
+ /* Special case UTF-8. Multi-byte chars start with any
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+ end = raw + (offset - pstr->mb_cur_max);
+ if (end < pstr->raw_mbs)
+ end = pstr->raw_mbs;
+ p = raw + offset - 1;
+#ifdef _LIBC
+ /* We know the wchar_t encoding is UCS4, so for the simple
+ case, ASCII characters, skip the conversion step. */
+ if (isascii (*p) && BE (pstr->trans == NULL, 1))
+ {
+ memset (&pstr->cur_state, '\0', sizeof (mbstate_t));
+ /* pstr->valid_len = 0; */
+ wc = (wchar_t) *p;
+ }
+ else
+#endif
+ for (; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+ mbstate_t cur_state;
+ wchar_t wc2;
+ int mlen = raw + pstr->len - p;
+ unsigned char buf[6];
+ size_t mbclen;
+
+ q = p;
+ if (BE (pstr->trans != NULL, 0))
+ {
+ int i = mlen < 6 ? mlen : 6;
+ while (--i >= 0)
+ buf[i] = pstr->trans[p[i]];
+ q = buf;
+ }
+ /* XXX Don't use mbrtowc, we know which conversion
+ to use (UTF-8 -> UCS4). */
+ memset (&cur_state, 0, sizeof (cur_state));
+ mbclen = mbrtowc (&wc2, (const char *) p, mlen,
+ &cur_state);
+ if (raw + offset - p <= mbclen
+ && mbclen < (size_t) -2)
+ {
+ memset (&pstr->cur_state, '\0',
+ sizeof (mbstate_t));
+ pstr->valid_len = mbclen - (raw + offset - p);
+ wc = wc2;
+ }
+ break;
+ }
+ }
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (wc == WEOF)
+ pstr->tip_context
+ = re_string_context_at (pstr, prev_valid_len - 1, eflags);
+ else
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
+ ? CONTEXT_WORD
+ : ((IS_WIDE_NEWLINE (wc)
+ && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+ pstr->wcs[wcs_idx] = WEOF;
+ if (pstr->mbs_allocated)
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
+ pstr->valid_raw_len = 0;
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
+ ? CONTEXT_WORD
+ : ((IS_NEWLINE (c) && pstr->newline_anchor)
+ ? CONTEXT_NEWLINE : 0));
+ }
+ }
+ if (!BE (pstr->mbs_allocated, 0))
+ pstr->mbs += offset;
+ }
+ pstr->raw_mbs_idx = idx;
+ pstr->len -= offset;
+ pstr->stop -= offset;
+
+ /* Then build the buffers. */
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ if (pstr->icase)
+ {
+ reg_errcode_t ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+ build_wcs_buffer (pstr);
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ if (BE (pstr->mbs_allocated, 0))
+ {
+ if (pstr->icase)
+ build_upper_buffer (pstr);
+ else if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ else
+ pstr->valid_len = pstr->len;
+
+ pstr->cur_idx = 0;
+ return REG_NOERROR;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_peek_byte_case (const re_string_t *pstr, int idx)
+{
+ int ch, off;
+
+ /* Handle the common (easiest) cases first. */
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_peek_byte (pstr, idx);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1
+ && ! re_string_is_single_byte_char (pstr, pstr->cur_idx + idx))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ off = pstr->cur_idx + idx;
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ off = pstr->offsets[off];
+#endif
+
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+#ifdef RE_ENABLE_I18N
+ /* Ensure that e.g. for tr_TR.UTF-8 BACKSLASH DOTLESS SMALL LETTER I
+ this function returns CAPITAL LETTER I instead of first byte of
+ DOTLESS SMALL LETTER I. The latter would confuse the parser,
+ since peek_byte_case doesn't advance cur_idx in any way. */
+ if (pstr->offsets_needed && !isascii (ch))
+ return re_string_peek_byte (pstr, idx);
+#endif
+
+ return ch;
+}
+
+static unsigned char
+internal_function __attribute ((pure))
+re_string_fetch_byte_case (re_string_t *pstr)
+{
+ if (BE (!pstr->mbs_allocated, 1))
+ return re_string_fetch_byte (pstr);
+
+#ifdef RE_ENABLE_I18N
+ if (pstr->offsets_needed)
+ {
+ int off, ch;
+
+ /* For tr_TR.UTF-8 [[:islower:]] there is
+ [[: CAPITAL LETTER I WITH DOT lower:]] in mbs. Skip
+ in that case the whole multi-byte character and return
+ the original letter. On the other side, with
+ [[: DOTLESS SMALL LETTER I return [[:I, as doing
+ anything else would complicate things too much. */
+
+ if (!re_string_first_byte (pstr, pstr->cur_idx))
+ return re_string_fetch_byte (pstr);
+
+ off = pstr->offsets[pstr->cur_idx];
+ ch = pstr->raw_mbs[pstr->raw_mbs_idx + off];
+
+ if (! isascii (ch))
+ return re_string_fetch_byte (pstr);
+
+ re_string_skip_bytes (pstr,
+ re_string_char_size_at (pstr, pstr->cur_idx));
+ return ch;
+ }
+#endif
+
+ return pstr->raw_mbs[pstr->raw_mbs_idx + pstr->cur_idx++];
+}
+
+static void
+internal_function
+re_string_destruct (re_string_t *pstr)
+{
+#ifdef RE_ENABLE_I18N
+ re_free (pstr->wcs);
+ re_free (pstr->offsets);
+#endif /* RE_ENABLE_I18N */
+ if (pstr->mbs_allocated)
+ re_free (pstr->mbs);
+}
+
+/* Return the context at IDX in INPUT. */
+
+static unsigned int
+internal_function
+re_string_context_at (const re_string_t *input, int idx, int eflags)
+{
+ int c;
+ if (BE (idx < 0, 0))
+ /* In this case, we use the value stored in input->tip_context,
+ since we can't know the character in input->mbs[-1] here. */
+ return input->tip_context;
+ if (BE (idx == input->len, 0))
+ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF
+ : CONTEXT_NEWLINE | CONTEXT_ENDBUF);
+#ifdef RE_ENABLE_I18N
+ if (input->mb_cur_max > 1)
+ {
+ wint_t wc;
+ int wc_idx = idx;
+ while(input->wcs[wc_idx] == WEOF)
+ {
+#ifdef DEBUG
+ /* It must not happen. */
+ assert (wc_idx >= 0);
+#endif
+ --wc_idx;
+ if (wc_idx < 0)
+ return input->tip_context;
+ }
+ wc = input->wcs[wc_idx];
+ if (BE (input->word_ops_used != 0, 0) && IS_WIDE_WORD_CHAR (wc))
+ return CONTEXT_WORD;
+ return (IS_WIDE_NEWLINE (wc) && input->newline_anchor
+ ? CONTEXT_NEWLINE : 0);
+ }
+ else
+#endif
+ {
+ c = re_string_byte_at (input, idx);
+ if (bitset_contain (input->word_char, c))
+ return CONTEXT_WORD;
+ return IS_NEWLINE (c) && input->newline_anchor ? CONTEXT_NEWLINE : 0;
+ }
+}
+
+/* Functions for set operation. */
+
+static reg_errcode_t
+internal_function
+re_node_set_alloc (re_node_set *set, int size)
+{
+ set->alloc = size;
+ set->nelem = 0;
+ set->elems = re_malloc (int, size);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_1 (re_node_set *set, int elem)
+{
+ set->alloc = 1;
+ set->nelem = 1;
+ set->elems = re_malloc (int, 1);
+ if (BE (set->elems == NULL, 0))
+ {
+ set->alloc = set->nelem = 0;
+ return REG_ESPACE;
+ }
+ set->elems[0] = elem;
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_2 (re_node_set *set, int elem1, int elem2)
+{
+ set->alloc = 2;
+ set->elems = re_malloc (int, 2);
+ if (BE (set->elems == NULL, 0))
+ return REG_ESPACE;
+ if (elem1 == elem2)
+ {
+ set->nelem = 1;
+ set->elems[0] = elem1;
+ }
+ else
+ {
+ set->nelem = 2;
+ if (elem1 < elem2)
+ {
+ set->elems[0] = elem1;
+ set->elems[1] = elem2;
+ }
+ else
+ {
+ set->elems[0] = elem2;
+ set->elems[1] = elem1;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+re_node_set_init_copy (re_node_set *dest, const re_node_set *src)
+{
+ dest->nelem = src->nelem;
+ if (src->nelem > 0)
+ {
+ dest->alloc = dest->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ {
+ dest->alloc = dest->nelem = 0;
+ return REG_ESPACE;
+ }
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ }
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+}
+
+/* Calculate the intersection of the sets SRC1 and SRC2. And merge it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded.
+ Note: We assume dest->elems is NULL, when dest->alloc is 0. */
+
+static reg_errcode_t
+internal_function
+re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, is, id, delta, sbase;
+ if (src1->nelem == 0 || src2->nelem == 0)
+ return REG_NOERROR;
+
+ /* We need dest->nelem + 2 * elems_in_intersection; this is a
+ conservative estimate. */
+ if (src1->nelem + src2->nelem + dest->nelem > dest->alloc)
+ {
+ int new_alloc = src1->nelem + src2->nelem + dest->alloc;
+ int *new_elems = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_elems == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_elems;
+ dest->alloc = new_alloc;
+ }
+
+ /* Find the items in the intersection of SRC1 and SRC2, and copy
+ into the top of DEST those that are not already in DEST itself. */
+ sbase = dest->nelem + src1->nelem + src2->nelem;
+ i1 = src1->nelem - 1;
+ i2 = src2->nelem - 1;
+ id = dest->nelem - 1;
+ for (;;)
+ {
+ if (src1->elems[i1] == src2->elems[i2])
+ {
+ /* Try to find the item in DEST. Maybe we could binary search? */
+ while (id >= 0 && dest->elems[id] > src1->elems[i1])
+ --id;
+
+ if (id < 0 || dest->elems[id] != src1->elems[i1])
+ dest->elems[--sbase] = src1->elems[i1];
+
+ if (--i1 < 0 || --i2 < 0)
+ break;
+ }
+
+ /* Lower the highest of the two items. */
+ else if (src1->elems[i1] < src2->elems[i2])
+ {
+ if (--i2 < 0)
+ break;
+ }
+ else
+ {
+ if (--i1 < 0)
+ break;
+ }
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + src1->nelem + src2->nelem - 1;
+ delta = is - sbase + 1;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place; this is more or
+ less the same loop that is in re_node_set_merge. */
+ dest->nelem += delta;
+ if (delta > 0 && id >= 0)
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ break;
+ }
+ }
+
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase, delta * sizeof (int));
+
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets SRC1 and SRC2. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_init_union (re_node_set *dest, const re_node_set *src1,
+ const re_node_set *src2)
+{
+ int i1, i2, id;
+ if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0)
+ {
+ dest->alloc = src1->nelem + src2->nelem;
+ dest->elems = re_malloc (int, dest->alloc);
+ if (BE (dest->elems == NULL, 0))
+ return REG_ESPACE;
+ }
+ else
+ {
+ if (src1 != NULL && src1->nelem > 0)
+ return re_node_set_init_copy (dest, src1);
+ else if (src2 != NULL && src2->nelem > 0)
+ return re_node_set_init_copy (dest, src2);
+ else
+ re_node_set_init_empty (dest);
+ return REG_NOERROR;
+ }
+ for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;)
+ {
+ if (src1->elems[i1] > src2->elems[i2])
+ {
+ dest->elems[id++] = src2->elems[i2++];
+ continue;
+ }
+ if (src1->elems[i1] == src2->elems[i2])
+ ++i2;
+ dest->elems[id++] = src1->elems[i1++];
+ }
+ if (i1 < src1->nelem)
+ {
+ memcpy (dest->elems + id, src1->elems + i1,
+ (src1->nelem - i1) * sizeof (int));
+ id += src1->nelem - i1;
+ }
+ else if (i2 < src2->nelem)
+ {
+ memcpy (dest->elems + id, src2->elems + i2,
+ (src2->nelem - i2) * sizeof (int));
+ id += src2->nelem - i2;
+ }
+ dest->nelem = id;
+ return REG_NOERROR;
+}
+
+/* Calculate the union set of the sets DEST and SRC. And store it to
+ DEST. Return value indicate the error code or REG_NOERROR if succeeded. */
+
+static reg_errcode_t
+internal_function
+re_node_set_merge (re_node_set *dest, const re_node_set *src)
+{
+ int is, id, sbase, delta;
+ if (src == NULL || src->nelem == 0)
+ return REG_NOERROR;
+ if (dest->alloc < 2 * src->nelem + dest->nelem)
+ {
+ int new_alloc = 2 * (src->nelem + dest->alloc);
+ int *new_buffer = re_realloc (dest->elems, int, new_alloc);
+ if (BE (new_buffer == NULL, 0))
+ return REG_ESPACE;
+ dest->elems = new_buffer;
+ dest->alloc = new_alloc;
+ }
+
+ if (BE (dest->nelem == 0, 0))
+ {
+ dest->nelem = src->nelem;
+ memcpy (dest->elems, src->elems, src->nelem * sizeof (int));
+ return REG_NOERROR;
+ }
+
+ /* Copy into the top of DEST the items of SRC that are not
+ found in DEST. Maybe we could binary search in DEST? */
+ for (sbase = dest->nelem + 2 * src->nelem,
+ is = src->nelem - 1, id = dest->nelem - 1; is >= 0 && id >= 0; )
+ {
+ if (dest->elems[id] == src->elems[is])
+ is--, id--;
+ else if (dest->elems[id] < src->elems[is])
+ dest->elems[--sbase] = src->elems[is--];
+ else /* if (dest->elems[id] > src->elems[is]) */
+ --id;
+ }
+
+ if (is >= 0)
+ {
+ /* If DEST is exhausted, the remaining items of SRC must be unique. */
+ sbase -= is + 1;
+ memcpy (dest->elems + sbase, src->elems, (is + 1) * sizeof (int));
+ }
+
+ id = dest->nelem - 1;
+ is = dest->nelem + 2 * src->nelem - 1;
+ delta = is - sbase + 1;
+ if (delta == 0)
+ return REG_NOERROR;
+
+ /* Now copy. When DELTA becomes zero, the remaining
+ DEST elements are already in place. */
+ dest->nelem += delta;
+ for (;;)
+ {
+ if (dest->elems[is] > dest->elems[id])
+ {
+ /* Copy from the top. */
+ dest->elems[id + delta--] = dest->elems[is--];
+ if (delta == 0)
+ break;
+ }
+ else
+ {
+ /* Slide from the bottom. */
+ dest->elems[id + delta] = dest->elems[id];
+ if (--id < 0)
+ {
+ /* Copy remaining SRC elements. */
+ memcpy (dest->elems, dest->elems + sbase,
+ delta * sizeof (int));
+ break;
+ }
+ }
+ }
+
+ return REG_NOERROR;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have ELEM.
+ return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert (re_node_set *set, int elem)
+{
+ int idx;
+ /* In case the set is empty. */
+ if (set->alloc == 0)
+ {
+ if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1))
+ return 1;
+ else
+ return -1;
+ }
+
+ if (BE (set->nelem, 0) == 0)
+ {
+ /* We already guaranteed above that set->alloc != 0. */
+ set->elems[0] = elem;
+ ++set->nelem;
+ return 1;
+ }
+
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = set->alloc * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Move the elements which follows the new element. Test the
+ first element separately to skip a check in the inner loop. */
+ if (elem < set->elems[0])
+ {
+ idx = 0;
+ for (idx = set->nelem; idx > 0; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+ else
+ {
+ for (idx = set->nelem; set->elems[idx - 1] > elem; idx--)
+ set->elems[idx] = set->elems[idx - 1];
+ }
+
+ /* Insert the new element. */
+ set->elems[idx] = elem;
+ ++set->nelem;
+ return 1;
+}
+
+/* Insert the new element ELEM to the re_node_set* SET.
+ SET should not already have any element greater than or equal to ELEM.
+ Return -1 if an error is occured, return 1 otherwise. */
+
+static int
+internal_function
+re_node_set_insert_last (re_node_set *set, int elem)
+{
+ /* Realloc if we need. */
+ if (set->alloc == set->nelem)
+ {
+ int *new_elems;
+ set->alloc = (set->alloc + 1) * 2;
+ new_elems = re_realloc (set->elems, int, set->alloc);
+ if (BE (new_elems == NULL, 0))
+ return -1;
+ set->elems = new_elems;
+ }
+
+ /* Insert the new element. */
+ set->elems[set->nelem++] = elem;
+ return 1;
+}
+
+/* Compare two node sets SET1 and SET2.
+ return 1 if SET1 and SET2 are equivalent, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_compare (const re_node_set *set1, const re_node_set *set2)
+{
+ int i;
+ if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem)
+ return 0;
+ for (i = set1->nelem ; --i >= 0 ; )
+ if (set1->elems[i] != set2->elems[i])
+ return 0;
+ return 1;
+}
+
+/* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */
+
+static int
+internal_function __attribute ((pure))
+re_node_set_contains (const re_node_set *set, int elem)
+{
+ unsigned int idx, right, mid;
+ if (set->nelem <= 0)
+ return 0;
+
+ /* Binary search the element. */
+ idx = 0;
+ right = set->nelem - 1;
+ while (idx < right)
+ {
+ mid = (idx + right) / 2;
+ if (set->elems[mid] < elem)
+ idx = mid + 1;
+ else
+ right = mid;
+ }
+ return set->elems[idx] == elem ? idx + 1 : 0;
+}
+
+static void
+internal_function
+re_node_set_remove_at (re_node_set *set, int idx)
+{
+ if (idx < 0 || idx >= set->nelem)
+ return;
+ --set->nelem;
+ for (; idx < set->nelem; idx++)
+ set->elems[idx] = set->elems[idx + 1];
+}
+
+
+/* Add the token TOKEN to dfa->nodes, and return the index of the token.
+ Or return -1, if an error will be occured. */
+
+static int
+internal_function
+re_dfa_add_node (re_dfa_t *dfa, re_token_t token)
+{
+ int type = token.type;
+ if (BE (dfa->nodes_len >= dfa->nodes_alloc, 0))
+ {
+ size_t new_nodes_alloc = dfa->nodes_alloc * 2;
+ int *new_nexts, *new_indices;
+ re_node_set *new_edests, *new_eclosures;
+ re_token_t *new_nodes;
+
+ /* Avoid overflows. */
+ if (BE (new_nodes_alloc < dfa->nodes_alloc, 0))
+ return -1;
+
+ new_nodes = re_realloc (dfa->nodes, re_token_t, new_nodes_alloc);
+ if (BE (new_nodes == NULL, 0))
+ return -1;
+ dfa->nodes = new_nodes;
+ new_nexts = re_realloc (dfa->nexts, int, new_nodes_alloc);
+ new_indices = re_realloc (dfa->org_indices, int, new_nodes_alloc);
+ new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc);
+ new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc);
+ if (BE (new_nexts == NULL || new_indices == NULL
+ || new_edests == NULL || new_eclosures == NULL, 0))
+ return -1;
+ dfa->nexts = new_nexts;
+ dfa->org_indices = new_indices;
+ dfa->edests = new_edests;
+ dfa->eclosures = new_eclosures;
+ dfa->nodes_alloc = new_nodes_alloc;
+ }
+ dfa->nodes[dfa->nodes_len] = token;
+ dfa->nodes[dfa->nodes_len].constraint = 0;
+#ifdef RE_ENABLE_I18N
+ dfa->nodes[dfa->nodes_len].accept_mb =
+ (type == OP_PERIOD && dfa->mb_cur_max > 1) || type == COMPLEX_BRACKET;
+#endif
+ dfa->nexts[dfa->nodes_len] = -1;
+ re_node_set_init_empty (dfa->edests + dfa->nodes_len);
+ re_node_set_init_empty (dfa->eclosures + dfa->nodes_len);
+ return dfa->nodes_len++;
+}
+
+static inline unsigned int
+internal_function
+calc_state_hash (const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash = nodes->nelem + context;
+ int i;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ hash += nodes->elems[i];
+ return hash;
+}
+
+/* Search for the state whose node_set is equivalent to NODES.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (BE (nodes->nelem == 0, 0))
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, 0);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (hash != state->hash)
+ continue;
+ if (re_node_set_compare (&state->nodes, nodes))
+ return state;
+ }
+
+ /* There are no appropriate state in the dfa, create the new one. */
+ new_state = create_ci_newstate (dfa, nodes, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Search for the state whose node_set is equivalent to NODES and
+ whose context is equivalent to CONTEXT.
+ Return the pointer to the state, if we found it in the DFA.
+ Otherwise create the new one and return it. In case of an error
+ return NULL and set the error code in ERR.
+ Note: - We assume NULL as the invalid state, then it is possible that
+ return value is NULL and ERR is REG_NOERROR.
+ - We never return non-NULL value in case of any errors, it is for
+ optimization. */
+
+static re_dfastate_t *
+internal_function
+re_acquire_state_context (reg_errcode_t *err, const re_dfa_t *dfa,
+ const re_node_set *nodes, unsigned int context)
+{
+ unsigned int hash;
+ re_dfastate_t *new_state;
+ struct re_state_table_entry *spot;
+ int i;
+ if (nodes->nelem == 0)
+ {
+ *err = REG_NOERROR;
+ return NULL;
+ }
+ hash = calc_state_hash (nodes, context);
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+
+ for (i = 0 ; i < spot->num ; i++)
+ {
+ re_dfastate_t *state = spot->array[i];
+ if (state->hash == hash
+ && state->context == context
+ && re_node_set_compare (state->entrance_nodes, nodes))
+ return state;
+ }
+ /* There are no appropriate state in `dfa', create the new one. */
+ new_state = create_cd_newstate (dfa, nodes, context, hash);
+ if (BE (new_state == NULL, 0))
+ *err = REG_ESPACE;
+
+ return new_state;
+}
+
+/* Finish initialization of the new state NEWSTATE, and using its hash value
+ HASH put in the appropriate bucket of DFA's state table. Return value
+ indicates the error code if failed. */
+
+static reg_errcode_t
+register_state (const re_dfa_t *dfa, re_dfastate_t *newstate,
+ unsigned int hash)
+{
+ struct re_state_table_entry *spot;
+ reg_errcode_t err;
+ int i;
+
+ newstate->hash = hash;
+ err = re_node_set_alloc (&newstate->non_eps_nodes, newstate->nodes.nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < newstate->nodes.nelem; i++)
+ {
+ int elem = newstate->nodes.elems[i];
+ if (!IS_EPSILON_NODE (dfa->nodes[elem].type))
+ re_node_set_insert_last (&newstate->non_eps_nodes, elem);
+ }
+
+ spot = dfa->state_table + (hash & dfa->state_hash_mask);
+ if (BE (spot->alloc <= spot->num, 0))
+ {
+ int new_alloc = 2 * spot->num + 2;
+ re_dfastate_t **new_array = re_realloc (spot->array, re_dfastate_t *,
+ new_alloc);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ spot->array = new_array;
+ spot->alloc = new_alloc;
+ }
+ spot->array[spot->num++] = newstate;
+ return REG_NOERROR;
+}
+
+static void
+free_state (re_dfastate_t *state)
+{
+ re_node_set_free (&state->non_eps_nodes);
+ re_node_set_free (&state->inveclosure);
+ if (state->entrance_nodes != &state->nodes)
+ {
+ re_node_set_free (state->entrance_nodes);
+ re_free (state->entrance_nodes);
+ }
+ re_node_set_free (&state->nodes);
+ re_free (state->word_trtable);
+ re_free (state->trtable);
+ re_free (state);
+}
+
+/* Create the new state which is independ of contexts.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_ci_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int hash)
+{
+ int i;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->entrance_nodes = &newstate->nodes;
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (type == CHARACTER && !node->constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR || node->constraint)
+ newstate->has_constraint = 1;
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
+
+/* Create the new state which is depend on the context CONTEXT.
+ Return the new state if succeeded, otherwise return NULL. */
+
+static re_dfastate_t *
+internal_function
+create_cd_newstate (const re_dfa_t *dfa, const re_node_set *nodes,
+ unsigned int context, unsigned int hash)
+{
+ int i, nctx_nodes = 0;
+ reg_errcode_t err;
+ re_dfastate_t *newstate;
+
+ newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1);
+ if (BE (newstate == NULL, 0))
+ return NULL;
+ err = re_node_set_init_copy (&newstate->nodes, nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_free (newstate);
+ return NULL;
+ }
+
+ newstate->context = context;
+ newstate->entrance_nodes = &newstate->nodes;
+
+ for (i = 0 ; i < nodes->nelem ; i++)
+ {
+ unsigned int constraint = 0;
+ re_token_t *node = dfa->nodes + nodes->elems[i];
+ re_token_type_t type = node->type;
+ if (node->constraint)
+ constraint = node->constraint;
+
+ if (type == CHARACTER && !constraint)
+ continue;
+#ifdef RE_ENABLE_I18N
+ newstate->accept_mb |= node->accept_mb;
+#endif /* RE_ENABLE_I18N */
+
+ /* If the state has the halt node, the state is a halt state. */
+ if (type == END_OF_RE)
+ newstate->halt = 1;
+ else if (type == OP_BACK_REF)
+ newstate->has_backref = 1;
+ else if (type == ANCHOR)
+ constraint = node->opr.ctx_type;
+
+ if (constraint)
+ {
+ if (newstate->entrance_nodes == &newstate->nodes)
+ {
+ newstate->entrance_nodes = re_malloc (re_node_set, 1);
+ if (BE (newstate->entrance_nodes == NULL, 0))
+ {
+ free_state (newstate);
+ return NULL;
+ }
+ re_node_set_init_copy (newstate->entrance_nodes, nodes);
+ nctx_nodes = 0;
+ newstate->has_constraint = 1;
+ }
+
+ if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context))
+ {
+ re_node_set_remove_at (&newstate->nodes, i - nctx_nodes);
+ ++nctx_nodes;
+ }
+ }
+ }
+ err = register_state (dfa, newstate, hash);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ free_state (newstate);
+ newstate = NULL;
+ }
+ return newstate;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.h b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.h
new file mode 100644
index 0000000..b0c4d35
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regex_internal.h
@@ -0,0 +1,778 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _REGEX_INTERNAL_H
+#define _REGEX_INTERNAL_H 1
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__MINGW32_VERSION) || defined(_MSC_VER)
+#define strcasecmp stricmp
+#endif
+
+#if defined HAVE_LANGINFO_H || defined HAVE_LANGINFO_CODESET || defined _LIBC
+# include <langinfo.h>
+#endif
+#if defined HAVE_LOCALE_H || defined _LIBC
+# include <locale.h>
+#endif
+#if defined HAVE_WCHAR_H || defined _LIBC
+# include <wchar.h>
+#endif /* HAVE_WCHAR_H || _LIBC */
+#if defined HAVE_WCTYPE_H || defined _LIBC
+# include <wctype.h>
+#endif /* HAVE_WCTYPE_H || _LIBC */
+#if defined HAVE_STDBOOL_H || defined _LIBC
+# include <stdbool.h>
+#else
+typedef enum { false, true } bool;
+#endif /* HAVE_STDBOOL_H || _LIBC */
+#if defined HAVE_STDINT_H || defined _LIBC
+# include <stdint.h>
+#endif /* HAVE_STDINT_H || _LIBC */
+#if defined _LIBC
+# include <bits/libc-lock.h>
+#else
+# define __libc_lock_define(CLASS,NAME)
+# define __libc_lock_init(NAME) do { } while (0)
+# define __libc_lock_lock(NAME) do { } while (0)
+# define __libc_lock_unlock(NAME) do { } while (0)
+#endif
+
+/* In case that the system doesn't have isblank(). */
+#if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank
+# define isblank(ch) ((ch) == ' ' || (ch) == '\t')
+#endif
+
+#ifdef _LIBC
+# ifndef _RE_DEFINE_LOCALE_FUNCTIONS
+# define _RE_DEFINE_LOCALE_FUNCTIONS 1
+# include <locale/localeinfo.h>
+# include <locale/elem-hash.h>
+# include <locale/coll-lookup.h>
+# endif
+#endif
+
+/* This is for other GNU distributions with internationalized messages. */
+#if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+# include <libintl.h>
+# ifdef _LIBC
+# undef gettext
+# define gettext(msgid) \
+ INTUSE(__dcgettext) (_libc_intl_domainname, msgid, LC_MESSAGES)
+# endif
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+# define gettext_noop(String) String
+#endif
+
+/* For loser systems without the definition. */
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
+#if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC
+# define RE_ENABLE_I18N
+#endif
+
+#if __GNUC__ >= 3
+# define BE(expr, val) __builtin_expect (expr, val)
+#else
+# define BE(expr, val) (expr)
+# define inline
+#endif
+
+/* Number of single byte character. */
+#define SBC_MAX 256
+
+#define COLL_ELEM_LEN_MAX 8
+
+/* The character which represents newline. */
+#define NEWLINE_CHAR '\n'
+#define WIDE_NEWLINE_CHAR L'\n'
+
+/* Rename to standard API for using out of glibc. */
+#ifndef _LIBC
+# define __wctype wctype
+# define __iswctype iswctype
+# define __btowc btowc
+# define __mempcpy mempcpy
+# define __wcrtomb wcrtomb
+# define __regfree regfree
+# define attribute_hidden
+#endif /* not _LIBC */
+
+#ifdef __GNUC__
+# define __attribute(arg) __attribute__ (arg)
+#else
+# define __attribute(arg)
+#endif
+
+extern const char __re_error_msgid[] attribute_hidden;
+extern const size_t __re_error_msgid_idx[] attribute_hidden;
+
+/* An integer used to represent a set of bits. It must be unsigned,
+ and must be at least as wide as unsigned int. */
+typedef unsigned long int bitset_word_t;
+/* All bits set in a bitset_word_t. */
+#define BITSET_WORD_MAX ULONG_MAX
+/* Number of bits in a bitset_word_t. */
+#define BITSET_WORD_BITS (sizeof (bitset_word_t) * CHAR_BIT)
+/* Number of bitset_word_t in a bit_set. */
+#define BITSET_WORDS (SBC_MAX / BITSET_WORD_BITS)
+typedef bitset_word_t bitset_t[BITSET_WORDS];
+typedef bitset_word_t *re_bitset_ptr_t;
+typedef const bitset_word_t *re_const_bitset_ptr_t;
+
+#define bitset_set(set,i) \
+ (set[i / BITSET_WORD_BITS] |= (bitset_word_t) 1 << i % BITSET_WORD_BITS)
+#define bitset_clear(set,i) \
+ (set[i / BITSET_WORD_BITS] &= ~((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_contain(set,i) \
+ (set[i / BITSET_WORD_BITS] & ((bitset_word_t) 1 << i % BITSET_WORD_BITS))
+#define bitset_empty(set) memset (set, '\0', sizeof (bitset_t))
+#define bitset_set_all(set) memset (set, '\xff', sizeof (bitset_t))
+#define bitset_copy(dest,src) memcpy (dest, src, sizeof (bitset_t))
+
+#define PREV_WORD_CONSTRAINT 0x0001
+#define PREV_NOTWORD_CONSTRAINT 0x0002
+#define NEXT_WORD_CONSTRAINT 0x0004
+#define NEXT_NOTWORD_CONSTRAINT 0x0008
+#define PREV_NEWLINE_CONSTRAINT 0x0010
+#define NEXT_NEWLINE_CONSTRAINT 0x0020
+#define PREV_BEGBUF_CONSTRAINT 0x0040
+#define NEXT_ENDBUF_CONSTRAINT 0x0080
+#define WORD_DELIM_CONSTRAINT 0x0100
+#define NOT_WORD_DELIM_CONSTRAINT 0x0200
+
+typedef enum
+{
+ INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT,
+ WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ INSIDE_NOTWORD = PREV_NOTWORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT,
+ LINE_FIRST = PREV_NEWLINE_CONSTRAINT,
+ LINE_LAST = NEXT_NEWLINE_CONSTRAINT,
+ BUF_FIRST = PREV_BEGBUF_CONSTRAINT,
+ BUF_LAST = NEXT_ENDBUF_CONSTRAINT,
+ WORD_DELIM = WORD_DELIM_CONSTRAINT,
+ NOT_WORD_DELIM = NOT_WORD_DELIM_CONSTRAINT
+} re_context_type;
+
+typedef struct
+{
+ int alloc;
+ int nelem;
+ int *elems;
+} re_node_set;
+
+typedef enum
+{
+ NON_TYPE = 0,
+
+ /* Node type, These are used by token, node, tree. */
+ CHARACTER = 1,
+ END_OF_RE = 2,
+ SIMPLE_BRACKET = 3,
+ OP_BACK_REF = 4,
+ OP_PERIOD = 5,
+#ifdef RE_ENABLE_I18N
+ COMPLEX_BRACKET = 6,
+ OP_UTF8_PERIOD = 7,
+#endif /* RE_ENABLE_I18N */
+
+ /* We define EPSILON_BIT as a macro so that OP_OPEN_SUBEXP is used
+ when the debugger shows values of this enum type. */
+#define EPSILON_BIT 8
+ OP_OPEN_SUBEXP = EPSILON_BIT | 0,
+ OP_CLOSE_SUBEXP = EPSILON_BIT | 1,
+ OP_ALT = EPSILON_BIT | 2,
+ OP_DUP_ASTERISK = EPSILON_BIT | 3,
+ ANCHOR = EPSILON_BIT | 4,
+
+ /* Tree type, these are used only by tree. */
+ CONCAT = 16,
+ SUBEXP = 17,
+
+ /* Token type, these are used only by token. */
+ OP_DUP_PLUS = 18,
+ OP_DUP_QUESTION,
+ OP_OPEN_BRACKET,
+ OP_CLOSE_BRACKET,
+ OP_CHARSET_RANGE,
+ OP_OPEN_DUP_NUM,
+ OP_CLOSE_DUP_NUM,
+ OP_NON_MATCH_LIST,
+ OP_OPEN_COLL_ELEM,
+ OP_CLOSE_COLL_ELEM,
+ OP_OPEN_EQUIV_CLASS,
+ OP_CLOSE_EQUIV_CLASS,
+ OP_OPEN_CHAR_CLASS,
+ OP_CLOSE_CHAR_CLASS,
+ OP_WORD,
+ OP_NOTWORD,
+ OP_SPACE,
+ OP_NOTSPACE,
+ BACK_SLASH
+
+} re_token_type_t;
+
+#ifdef RE_ENABLE_I18N
+typedef struct
+{
+ /* Multibyte characters. */
+ wchar_t *mbchars;
+
+ /* Collating symbols. */
+# ifdef _LIBC
+ int32_t *coll_syms;
+# endif
+
+ /* Equivalence classes. */
+# ifdef _LIBC
+ int32_t *equiv_classes;
+# endif
+
+ /* Range expressions. */
+# ifdef _LIBC
+ uint32_t *range_starts;
+ uint32_t *range_ends;
+# else /* not _LIBC */
+ wchar_t *range_starts;
+ wchar_t *range_ends;
+# endif /* not _LIBC */
+
+ /* Character classes. */
+ wctype_t *char_classes;
+
+ /* If this character set is the non-matching list. */
+ unsigned int non_match : 1;
+
+ /* # of multibyte characters. */
+ int nmbchars;
+
+ /* # of collating symbols. */
+ int ncoll_syms;
+
+ /* # of equivalence classes. */
+ int nequiv_classes;
+
+ /* # of range expressions. */
+ int nranges;
+
+ /* # of character classes. */
+ int nchar_classes;
+} re_charset_t;
+#endif /* RE_ENABLE_I18N */
+
+typedef struct
+{
+ union
+ {
+ unsigned char c; /* for CHARACTER */
+ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */
+#ifdef RE_ENABLE_I18N
+ re_charset_t *mbcset; /* for COMPLEX_BRACKET */
+#endif /* RE_ENABLE_I18N */
+ int idx; /* for BACK_REF */
+ re_context_type ctx_type; /* for ANCHOR */
+ } opr;
+#if __GNUC__ >= 2
+ re_token_type_t type : 8;
+#else
+ re_token_type_t type;
+#endif
+ unsigned int constraint : 10; /* context constraint */
+ unsigned int duplicated : 1;
+ unsigned int opt_subexp : 1;
+#ifdef RE_ENABLE_I18N
+ unsigned int accept_mb : 1;
+ /* These 2 bits can be moved into the union if needed (e.g. if running out
+ of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */
+ unsigned int mb_partial : 1;
+#endif
+ unsigned int word_char : 1;
+} re_token_t;
+
+#define IS_EPSILON_NODE(type) ((type) & EPSILON_BIT)
+
+struct re_string_t
+{
+ /* Indicate the raw buffer which is the original string passed as an
+ argument of regexec(), re_search(), etc.. */
+ const unsigned char *raw_mbs;
+ /* Store the multibyte string. In case of "case insensitive mode" like
+ REG_ICASE, upper cases of the string are stored, otherwise MBS points
+ the same address that RAW_MBS points. */
+ unsigned char *mbs;
+#ifdef RE_ENABLE_I18N
+ /* Store the wide character string which is corresponding to MBS. */
+ wint_t *wcs;
+ int *offsets;
+ mbstate_t cur_state;
+#endif
+ /* Index in RAW_MBS. Each character mbs[i] corresponds to
+ raw_mbs[raw_mbs_idx + i]. */
+ int raw_mbs_idx;
+ /* The length of the valid characters in the buffers. */
+ int valid_len;
+ /* The corresponding number of bytes in raw_mbs array. */
+ int valid_raw_len;
+ /* The length of the buffers MBS and WCS. */
+ int bufs_len;
+ /* The index in MBS, which is updated by re_string_fetch_byte. */
+ int cur_idx;
+ /* length of RAW_MBS array. */
+ int raw_len;
+ /* This is RAW_LEN - RAW_MBS_IDX + VALID_LEN - VALID_RAW_LEN. */
+ int len;
+ /* End of the buffer may be shorter than its length in the cases such
+ as re_match_2, re_search_2. Then, we use STOP for end of the buffer
+ instead of LEN. */
+ int raw_stop;
+ /* This is RAW_STOP - RAW_MBS_IDX adjusted through OFFSETS. */
+ int stop;
+
+ /* The context of mbs[0]. We store the context independently, since
+ the context of mbs[0] may be different from raw_mbs[0], which is
+ the beginning of the input string. */
+ unsigned int tip_context;
+ /* The translation passed as a part of an argument of re_compile_pattern. */
+ RE_TRANSLATE_TYPE trans;
+ /* Copy of re_dfa_t's word_char. */
+ re_const_bitset_ptr_t word_char;
+ /* 1 if REG_ICASE. */
+ unsigned char icase;
+ unsigned char is_utf8;
+ unsigned char map_notascii;
+ unsigned char mbs_allocated;
+ unsigned char offsets_needed;
+ unsigned char newline_anchor;
+ unsigned char word_ops_used;
+ int mb_cur_max;
+};
+typedef struct re_string_t re_string_t;
+
+
+struct re_dfa_t;
+typedef struct re_dfa_t re_dfa_t;
+
+#ifndef _LIBC
+# ifdef __i386__
+# define internal_function __attribute ((regparm (3), stdcall))
+# else
+# define internal_function
+# endif
+#endif
+
+static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr,
+ int new_buf_len)
+ internal_function;
+#ifdef RE_ENABLE_I18N
+static void build_wcs_buffer (re_string_t *pstr) internal_function;
+static int build_wcs_upper_buffer (re_string_t *pstr) internal_function;
+#endif /* RE_ENABLE_I18N */
+static void build_upper_buffer (re_string_t *pstr) internal_function;
+static void re_string_translate_buffer (re_string_t *pstr) internal_function;
+static unsigned int re_string_context_at (const re_string_t *input, int idx,
+ int eflags)
+ internal_function __attribute ((pure));
+#define re_string_peek_byte(pstr, offset) \
+ ((pstr)->mbs[(pstr)->cur_idx + offset])
+#define re_string_fetch_byte(pstr) \
+ ((pstr)->mbs[(pstr)->cur_idx++])
+#define re_string_first_byte(pstr, idx) \
+ ((idx) == (pstr)->valid_len || (pstr)->wcs[idx] != WEOF)
+#define re_string_is_single_byte_char(pstr, idx) \
+ ((pstr)->wcs[idx] != WEOF && ((pstr)->valid_len == (idx) + 1 \
+ || (pstr)->wcs[(idx) + 1] != WEOF))
+#define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx)
+#define re_string_cur_idx(pstr) ((pstr)->cur_idx)
+#define re_string_get_buffer(pstr) ((pstr)->mbs)
+#define re_string_length(pstr) ((pstr)->len)
+#define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx])
+#define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx))
+#define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx))
+
+#ifdef __GNUC__
+# define alloca(size) __builtin_alloca (size)
+# define HAVE_ALLOCA 1
+#elif defined(_MSC_VER)
+# include <malloc.h>
+# define alloca _alloca
+# define HAVE_ALLOCA 1
+#else
+# error No alloca()
+#endif
+
+#ifndef _LIBC
+# if HAVE_ALLOCA
+/* The OS usually guarantees only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ allocate anything larger than 4096 bytes. Also care for the possibility
+ of a few compiler-allocated temporary stack slots. */
+# define __libc_use_alloca(n) ((n) < 4032)
+# else
+/* alloca is implemented with malloc, so just use malloc. */
+# define __libc_use_alloca(n) 0
+# endif
+#endif
+
+#define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t)))
+#define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t)))
+#define re_free(p) free (p)
+
+struct bin_tree_t
+{
+ struct bin_tree_t *parent;
+ struct bin_tree_t *left;
+ struct bin_tree_t *right;
+ struct bin_tree_t *first;
+ struct bin_tree_t *next;
+
+ re_token_t token;
+
+ /* `node_idx' is the index in dfa->nodes, if `type' == 0.
+ Otherwise `type' indicate the type of this node. */
+ int node_idx;
+};
+typedef struct bin_tree_t bin_tree_t;
+
+#define BIN_TREE_STORAGE_SIZE \
+ ((1024 - sizeof (void *)) / sizeof (bin_tree_t))
+
+struct bin_tree_storage_t
+{
+ struct bin_tree_storage_t *next;
+ bin_tree_t data[BIN_TREE_STORAGE_SIZE];
+};
+typedef struct bin_tree_storage_t bin_tree_storage_t;
+
+#define CONTEXT_WORD 1
+#define CONTEXT_NEWLINE (CONTEXT_WORD << 1)
+#define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1)
+#define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1)
+
+#define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD)
+#define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE)
+#define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF)
+#define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF)
+#define IS_ORDINARY_CONTEXT(c) ((c) == 0)
+
+#define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_')
+#define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR)
+#define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_')
+#define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR)
+
+#define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \
+ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\
+ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context)))
+
+#define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \
+ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \
+ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \
+ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context)))
+
+struct re_dfastate_t
+{
+ unsigned int hash;
+ re_node_set nodes;
+ re_node_set non_eps_nodes;
+ re_node_set inveclosure;
+ re_node_set *entrance_nodes;
+ struct re_dfastate_t **trtable, **word_trtable;
+ unsigned int context : 4;
+ unsigned int halt : 1;
+ /* If this state can accept `multi byte'.
+ Note that we refer to multibyte characters, and multi character
+ collating elements as `multi byte'. */
+ unsigned int accept_mb : 1;
+ /* If this state has backreference node(s). */
+ unsigned int has_backref : 1;
+ unsigned int has_constraint : 1;
+};
+typedef struct re_dfastate_t re_dfastate_t;
+
+struct re_state_table_entry
+{
+ int num;
+ int alloc;
+ re_dfastate_t **array;
+};
+
+/* Array type used in re_sub_match_last_t and re_sub_match_top_t. */
+
+typedef struct
+{
+ int next_idx;
+ int alloc;
+ re_dfastate_t **array;
+} state_array_t;
+
+/* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */
+
+typedef struct
+{
+ int node;
+ int str_idx; /* The position NODE match at. */
+ state_array_t path;
+} re_sub_match_last_t;
+
+/* Store information about the node NODE whose type is OP_OPEN_SUBEXP.
+ And information about the node, whose type is OP_CLOSE_SUBEXP,
+ corresponding to NODE is stored in LASTS. */
+
+typedef struct
+{
+ int str_idx;
+ int node;
+ state_array_t *path;
+ int alasts; /* Allocation size of LASTS. */
+ int nlasts; /* The number of LASTS. */
+ re_sub_match_last_t **lasts;
+} re_sub_match_top_t;
+
+struct re_backref_cache_entry
+{
+ int node;
+ int str_idx;
+ int subexp_from;
+ int subexp_to;
+ char more;
+ char unused;
+ unsigned short int eps_reachable_subexps_map;
+};
+
+typedef struct
+{
+ /* The string object corresponding to the input string. */
+ re_string_t input;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ const re_dfa_t *const dfa;
+#else
+ const re_dfa_t *dfa;
+#endif
+ /* EFLAGS of the argument of regexec. */
+ int eflags;
+ /* Where the matching ends. */
+ int match_last;
+ int last_node;
+ /* The state log used by the matcher. */
+ re_dfastate_t **state_log;
+ int state_log_top;
+ /* Back reference cache. */
+ int nbkref_ents;
+ int abkref_ents;
+ struct re_backref_cache_entry *bkref_ents;
+ int max_mb_elem_len;
+ int nsub_tops;
+ int asub_tops;
+ re_sub_match_top_t **sub_tops;
+} re_match_context_t;
+
+typedef struct
+{
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **limited_states;
+ int last_node;
+ int last_str_idx;
+ re_node_set limits;
+} re_sift_context_t;
+
+struct re_fail_stack_ent_t
+{
+ int idx;
+ int node;
+ regmatch_t *regs;
+ re_node_set eps_via_nodes;
+};
+
+struct re_fail_stack_t
+{
+ int num;
+ int alloc;
+ struct re_fail_stack_ent_t *stack;
+};
+
+struct re_dfa_t
+{
+ re_token_t *nodes;
+ size_t nodes_alloc;
+ size_t nodes_len;
+ int *nexts;
+ int *org_indices;
+ re_node_set *edests;
+ re_node_set *eclosures;
+ re_node_set *inveclosures;
+ struct re_state_table_entry *state_table;
+ re_dfastate_t *init_state;
+ re_dfastate_t *init_state_word;
+ re_dfastate_t *init_state_nl;
+ re_dfastate_t *init_state_begbuf;
+ bin_tree_t *str_tree;
+ bin_tree_storage_t *str_tree_storage;
+ re_bitset_ptr_t sb_char;
+ int str_tree_storage_idx;
+
+ /* number of subexpressions `re_nsub' is in regex_t. */
+ unsigned int state_hash_mask;
+ int init_node;
+ int nbackref; /* The number of backreference in this dfa. */
+
+ /* Bitmap expressing which backreference is used. */
+ bitset_word_t used_bkref_map;
+ bitset_word_t completed_bkref_map;
+
+ unsigned int has_plural_match : 1;
+ /* If this dfa has "multibyte node", which is a backreference or
+ a node which can accept multibyte character or multi character
+ collating element. */
+ unsigned int has_mb_node : 1;
+ unsigned int is_utf8 : 1;
+ unsigned int map_notascii : 1;
+ unsigned int word_ops_used : 1;
+ int mb_cur_max;
+ bitset_t word_char;
+ reg_syntax_t syntax;
+ int *subexp_map;
+#ifdef DEBUG
+ char* re_str;
+#endif
+ __libc_lock_define (, lock)
+};
+
+#define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set))
+#define re_node_set_remove(set,id) \
+ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1))
+#define re_node_set_empty(p) ((p)->nelem = 0)
+#define re_node_set_free(set) re_free ((set)->elems)
+
+
+typedef enum
+{
+ SB_CHAR,
+ MB_CHAR,
+ EQUIV_CLASS,
+ COLL_SYM,
+ CHAR_CLASS
+} bracket_elem_type;
+
+typedef struct
+{
+ bracket_elem_type type;
+ union
+ {
+ unsigned char ch;
+ unsigned char *name;
+ wchar_t wch;
+ } opr;
+} bracket_elem_t;
+
+
+/* Inline functions for bitset operation. */
+static inline void
+bitset_not (bitset_t set)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ set[bitset_i] = ~set[bitset_i];
+}
+
+static inline void
+bitset_merge (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] |= src[bitset_i];
+}
+
+static inline void
+bitset_mask (bitset_t dest, const bitset_t src)
+{
+ int bitset_i;
+ for (bitset_i = 0; bitset_i < BITSET_WORDS; ++bitset_i)
+ dest[bitset_i] &= src[bitset_i];
+}
+
+#ifdef RE_ENABLE_I18N
+/* Inline functions for re_string. */
+static inline int
+internal_function __attribute ((pure))
+re_string_char_size_at (const re_string_t *pstr, int idx)
+{
+ int byte_idx;
+ if (pstr->mb_cur_max == 1)
+ return 1;
+ for (byte_idx = 1; idx + byte_idx < pstr->valid_len; ++byte_idx)
+ if (pstr->wcs[idx + byte_idx] != WEOF)
+ break;
+ return byte_idx;
+}
+
+static inline wint_t
+internal_function __attribute ((pure))
+re_string_wchar_at (const re_string_t *pstr, int idx)
+{
+ if (pstr->mb_cur_max == 1)
+ return (wint_t) pstr->mbs[idx];
+ return (wint_t) pstr->wcs[idx];
+}
+
+static int
+internal_function __attribute ((pure))
+re_string_elem_size_at (const re_string_t *pstr, int idx)
+{
+# ifdef _LIBC
+ const unsigned char *p, *extra;
+ const int32_t *table, *indirect;
+ int32_t tmp;
+# include <locale/weight.h>
+ uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+
+ if (nrules != 0)
+ {
+ table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE,
+ _NL_COLLATE_INDIRECTMB);
+ p = pstr->mbs + idx;
+ tmp = findidx (&p);
+ return p - pstr->mbs - idx;
+ }
+ else
+# endif /* _LIBC */
+ return 1;
+}
+#endif /* RE_ENABLE_I18N */
+
+#endif /* _REGEX_INTERNAL_H */
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regexec.c b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regexec.c
new file mode 100644
index 0000000..3c41f54
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/libgnurx-2.5/regexec.c
@@ -0,0 +1,4329 @@
+/* Extended regular expression matching and search library.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags,
+ int n) internal_function;
+static void match_ctx_clean (re_match_context_t *mctx) internal_function;
+static void match_ctx_free (re_match_context_t *cache) internal_function;
+static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node,
+ int str_idx, int from, int to)
+ internal_function;
+static int search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+ internal_function;
+static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node,
+ int str_idx) internal_function;
+static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop,
+ int node, int str_idx)
+ internal_function;
+static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node,
+ int last_str_idx)
+ internal_function;
+static reg_errcode_t re_search_internal (const regex_t *preg,
+ const char *string, int length,
+ int start, int range, int stop,
+ size_t nmatch, regmatch_t pmatch[],
+ int eflags) internal_function;
+static int re_search_2_stub (struct re_pattern_buffer *bufp,
+ const char *string1, int length1,
+ const char *string2, int length2,
+ int start, int range, struct re_registers *regs,
+ int stop, int ret_len) internal_function;
+static int re_search_stub (struct re_pattern_buffer *bufp,
+ const char *string, int length, int start,
+ int range, int stop, struct re_registers *regs,
+ int ret_len) internal_function;
+static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch,
+ int nregs, int regs_allocated) internal_function;
+static reg_errcode_t prune_impossible_nodes (re_match_context_t *mctx)
+ internal_function;
+static int check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first) internal_function;
+static int check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+ internal_function;
+static void update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node,
+ int cur_idx, int nmatch) internal_function;
+static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs,
+ int str_idx, int dest_node, int nregs,
+ regmatch_t *regs,
+ re_node_set *eps_via_nodes)
+ internal_function;
+static reg_errcode_t set_regs (const regex_t *preg,
+ const re_match_context_t *mctx,
+ size_t nmatch, regmatch_t *pmatch,
+ int fl_backtrack) internal_function;
+static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs)
+ internal_function;
+
+#ifdef RE_ENABLE_I18N
+static int sift_states_iter_mb (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+ internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t sift_states_backward (const re_match_context_t *mctx,
+ re_sift_context_t *sctx)
+ internal_function;
+static reg_errcode_t build_sifted_states (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *cur_dest)
+ internal_function;
+static reg_errcode_t update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx,
+ re_node_set *dest_nodes)
+ internal_function;
+static reg_errcode_t add_epsilon_src_nodes (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates)
+ internal_function;
+static int check_dst_limits (const re_match_context_t *mctx,
+ re_node_set *limits,
+ int dst_node, int dst_idx, int src_node,
+ int src_idx) internal_function;
+static int check_dst_limits_calc_pos_1 (const re_match_context_t *mctx,
+ int boundaries, int subexp_idx,
+ int from_node, int bkref_idx)
+ internal_function;
+static int check_dst_limits_calc_pos (const re_match_context_t *mctx,
+ int limit, int subexp_idx,
+ int node, int str_idx,
+ int bkref_idx) internal_function;
+static reg_errcode_t check_subexp_limits (const re_dfa_t *dfa,
+ re_node_set *dest_nodes,
+ const re_node_set *candidates,
+ re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents,
+ int str_idx) internal_function;
+static reg_errcode_t sift_states_bkref (const re_match_context_t *mctx,
+ re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+ internal_function;
+static reg_errcode_t merge_state_array (const re_dfa_t *dfa,
+ re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+ internal_function;
+static re_dfastate_t *find_recover_state (reg_errcode_t *err,
+ re_match_context_t *mctx) internal_function;
+static re_dfastate_t *transit_state (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *state) internal_function;
+static re_dfastate_t *merge_state_with_log (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+ internal_function;
+static reg_errcode_t check_subexp_matching_top (re_match_context_t *mctx,
+ re_node_set *cur_nodes,
+ int str_idx) internal_function;
+#if 0
+static re_dfastate_t *transit_state_sb (reg_errcode_t *err,
+ re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t transit_state_mb (re_match_context_t *mctx,
+ re_dfastate_t *pstate)
+ internal_function;
+#endif /* RE_ENABLE_I18N */
+static reg_errcode_t transit_state_bkref (re_match_context_t *mctx,
+ const re_node_set *nodes)
+ internal_function;
+static reg_errcode_t get_subexp (re_match_context_t *mctx,
+ int bkref_node, int bkref_str_idx)
+ internal_function;
+static reg_errcode_t get_subexp_sub (re_match_context_t *mctx,
+ const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last,
+ int bkref_node, int bkref_str)
+ internal_function;
+static int find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type) internal_function;
+static reg_errcode_t check_arrival (re_match_context_t *mctx,
+ state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str,
+ int type) internal_function;
+static reg_errcode_t check_arrival_add_next_nodes (re_match_context_t *mctx,
+ int str_idx,
+ re_node_set *cur_nodes,
+ re_node_set *next_nodes)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl (const re_dfa_t *dfa,
+ re_node_set *cur_nodes,
+ int ex_subexp, int type)
+ internal_function;
+static reg_errcode_t check_arrival_expand_ecl_sub (const re_dfa_t *dfa,
+ re_node_set *dst_nodes,
+ int target, int ex_subexp,
+ int type) internal_function;
+static reg_errcode_t expand_bkref_cache (re_match_context_t *mctx,
+ re_node_set *cur_nodes, int cur_str,
+ int subexp_num, int type)
+ internal_function;
+static int build_trtable (const re_dfa_t *dfa,
+ re_dfastate_t *state) internal_function;
+#ifdef RE_ENABLE_I18N
+static int check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int idx)
+ internal_function;
+# ifdef _LIBC
+static unsigned int find_collation_sequence_value (const unsigned char *mbs,
+ size_t name_len)
+ internal_function;
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+static int group_nodes_into_DFAstates (const re_dfa_t *dfa,
+ const re_dfastate_t *state,
+ re_node_set *states_node,
+ bitset_t *states_ch) internal_function;
+static int check_node_accept (const re_match_context_t *mctx,
+ const re_token_t *node, int idx)
+ internal_function;
+static reg_errcode_t extend_buffers (re_match_context_t *mctx)
+ internal_function;
+
+/* Entry point for POSIX code. */
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *__restrict preg;
+ const char *__restrict string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ reg_errcode_t err;
+ int start, length;
+ re_dfa_t *dfa = (re_dfa_t *) preg->buffer;
+
+ if (eflags & ~(REG_NOTBOL | REG_NOTEOL | REG_STARTEND))
+ return REG_BADPAT;
+
+ if (eflags & REG_STARTEND)
+ {
+ start = pmatch[0].rm_so;
+ length = pmatch[0].rm_eo;
+ }
+ else
+ {
+ start = 0;
+ length = strlen (string);
+ }
+
+ __libc_lock_lock (dfa->lock);
+ if (preg->no_sub)
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, 0, NULL, eflags);
+ else
+ err = re_search_internal (preg, string, length, start, length - start,
+ length, nmatch, pmatch, eflags);
+ __libc_lock_unlock (dfa->lock);
+ return err != REG_NOERROR;
+}
+
+#ifdef _LIBC
+# include <shlib-compat.h>
+versioned_symbol (libc, __regexec, regexec, GLIBC_2_3_4);
+
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+__typeof__ (__regexec) __compat_regexec;
+
+int
+attribute_compat_text_section
+__compat_regexec (const regex_t *__restrict preg,
+ const char *__restrict string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+ return regexec (preg, string, nmatch, pmatch,
+ eflags & (REG_NOTBOL | REG_NOTEOL));
+}
+compat_symbol (libc, __compat_regexec, regexec, GLIBC_2_0);
+# endif
+#endif
+
+/* Entry points for GNU code. */
+
+/* re_match, re_search, re_match_2, re_search_2
+
+ The former two functions operate on STRING with length LENGTH,
+ while the later two operate on concatenation of STRING1 and STRING2
+ with lengths LENGTH1 and LENGTH2, respectively.
+
+ re_match() matches the compiled pattern in BUFP against the string,
+ starting at index START.
+
+ re_search() first tries matching at index START, then it tries to match
+ starting from index START + 1, and so on. The last start position tried
+ is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same
+ way as re_match().)
+
+ The parameter STOP of re_{match,search}_2 specifies that no match exceeding
+ the first STOP characters of the concatenation of the strings should be
+ concerned.
+
+ If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match
+ and all groups is stroed in REGS. (For the "_2" variants, the offsets are
+ computed relative to the concatenation, not relative to the individual
+ strings.)
+
+ On success, re_match* functions return the length of the match, re_search*
+ return the position of the start of the match. Return value -1 means no
+ match was found and -2 indicates an internal error. */
+
+int
+re_match (bufp, string, length, start, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, 0, length, regs, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match, re_match)
+#endif
+
+int
+re_search (bufp, string, length, start, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range;
+ struct re_registers *regs;
+{
+ return re_search_stub (bufp, string, length, start, range, length, regs, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search, re_search)
+#endif
+
+int
+re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, 0, regs, stop, 1);
+}
+#ifdef _LIBC
+weak_alias (__re_match_2, re_match_2)
+#endif
+
+int
+re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop;
+ struct re_registers *regs;
+{
+ return re_search_2_stub (bufp, string1, length1, string2, length2,
+ start, range, regs, stop, 0);
+}
+#ifdef _LIBC
+weak_alias (__re_search_2, re_search_2)
+#endif
+
+static int
+re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs,
+ stop, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int length1, length2, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ const char *str;
+ int rval;
+ int len = length1 + length2;
+ int free_str = 0;
+
+ if (BE (length1 < 0 || length2 < 0 || stop < 0, 0))
+ return -2;
+
+ /* Concatenate the strings. */
+ if (length2 > 0)
+ if (length1 > 0)
+ {
+ char *s = re_malloc (char, len);
+
+ if (BE (s == NULL, 0))
+ return -2;
+#ifdef _LIBC
+ memcpy (__mempcpy (s, string1, length1), string2, length2);
+#else
+ memcpy (s, string1, length1);
+ memcpy (s + length1, string2, length2);
+#endif
+ str = s;
+ free_str = 1;
+ }
+ else
+ str = string2;
+ else
+ str = string1;
+
+ rval = re_search_stub (bufp, str, len, start, range, stop, regs,
+ ret_len);
+ if (free_str)
+ re_free ((char *) str);
+ return rval;
+}
+
+/* The parameters have the same meaning as those of re_search.
+ Additional parameters:
+ If RET_LEN is nonzero the length of the match is returned (re_match style);
+ otherwise the position of the match is returned. */
+
+static int
+re_search_stub (bufp, string, length, start, range, stop, regs, ret_len)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int length, start, range, stop, ret_len;
+ struct re_registers *regs;
+{
+ reg_errcode_t result;
+ regmatch_t *pmatch;
+ int nregs, rval;
+ int eflags = 0;
+ re_dfa_t *dfa = (re_dfa_t *) bufp->buffer;
+
+ /* Check for out-of-range. */
+ if (BE (start < 0 || start > length, 0))
+ return -1;
+ if (BE (start + range > length, 0))
+ range = length - start;
+ else if (BE (start + range < 0, 0))
+ range = -start;
+
+ __libc_lock_lock (dfa->lock);
+
+ eflags |= (bufp->not_bol) ? REG_NOTBOL : 0;
+ eflags |= (bufp->not_eol) ? REG_NOTEOL : 0;
+
+ /* Compile fastmap if we haven't yet. */
+ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate)
+ re_compile_fastmap (bufp);
+
+ if (BE (bufp->no_sub, 0))
+ regs = NULL;
+
+ /* We need at least 1 register. */
+ if (regs == NULL)
+ nregs = 1;
+ else if (BE (bufp->regs_allocated == REGS_FIXED &&
+ regs->num_regs < bufp->re_nsub + 1, 0))
+ {
+ nregs = regs->num_regs;
+ if (BE (nregs < 1, 0))
+ {
+ /* Nothing can be copied to regs. */
+ regs = NULL;
+ nregs = 1;
+ }
+ }
+ else
+ nregs = bufp->re_nsub + 1;
+ pmatch = re_malloc (regmatch_t, nregs);
+ if (BE (pmatch == NULL, 0))
+ {
+ rval = -2;
+ goto out;
+ }
+
+ result = re_search_internal (bufp, string, length, start, range, stop,
+ nregs, pmatch, eflags);
+
+ rval = 0;
+
+ /* I hope we needn't fill ther regs with -1's when no match was found. */
+ if (result != REG_NOERROR)
+ rval = -1;
+ else if (regs != NULL)
+ {
+ /* If caller wants register contents data back, copy them. */
+ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs,
+ bufp->regs_allocated);
+ if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0))
+ rval = -2;
+ }
+
+ if (BE (rval == 0, 1))
+ {
+ if (ret_len)
+ {
+ assert (pmatch[0].rm_so == start);
+ rval = pmatch[0].rm_eo - start;
+ }
+ else
+ rval = pmatch[0].rm_so;
+ }
+ re_free (pmatch);
+ out:
+ __libc_lock_unlock (dfa->lock);
+ return rval;
+}
+
+static unsigned
+re_copy_regs (regs, pmatch, nregs, regs_allocated)
+ struct re_registers *regs;
+ regmatch_t *pmatch;
+ int nregs, regs_allocated;
+{
+ int rval = REGS_REALLOCATE;
+ int i;
+ int need_regs = nregs + 1;
+ /* We need one extra element beyond `num_regs' for the `-1' marker GNU code
+ uses. */
+
+ /* Have the register data arrays been allocated? */
+ if (regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. */
+ regs->start = re_malloc (regoff_t, need_regs);
+ regs->end = re_malloc (regoff_t, need_regs);
+ if (BE (regs->start == NULL, 0) || BE (regs->end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->num_regs = need_regs;
+ }
+ else if (regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (BE (need_regs > regs->num_regs, 0))
+ {
+ regoff_t *new_start = re_realloc (regs->start, regoff_t, need_regs);
+ regoff_t *new_end = re_realloc (regs->end, regoff_t, need_regs);
+ if (BE (new_start == NULL, 0) || BE (new_end == NULL, 0))
+ return REGS_UNALLOCATED;
+ regs->start = new_start;
+ regs->end = new_end;
+ regs->num_regs = need_regs;
+ }
+ }
+ else
+ {
+ assert (regs_allocated == REGS_FIXED);
+ /* This function may not be called with REGS_FIXED and nregs too big. */
+ assert (regs->num_regs >= nregs);
+ rval = REGS_FIXED;
+ }
+
+ /* Copy the regs. */
+ for (i = 0; i < nregs; ++i)
+ {
+ regs->start[i] = pmatch[i].rm_so;
+ regs->end[i] = pmatch[i].rm_eo;
+ }
+ for ( ; i < regs->num_regs; ++i)
+ regs->start[i] = regs->end[i] = -1;
+
+ return rval;
+}
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+#ifdef _LIBC
+weak_alias (__re_set_registers, re_set_registers)
+#endif
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined _REGEX_RE_COMP || defined _LIBC
+int
+# ifdef _LIBC
+weak_function
+# endif
+re_exec (s)
+ const char *s;
+{
+ return 0 == regexec (&re_comp_buf, s, 0, NULL, 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* Internal entry point. */
+
+/* Searches for a compiled pattern PREG in the string STRING, whose
+ length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same
+ mingings with regexec. START, and RANGE have the same meanings
+ with re_search.
+ Return REG_NOERROR if we find a match, and REG_NOMATCH if not,
+ otherwise return the error code.
+ Note: We assume front end functions already check ranges.
+ (START + RANGE >= 0 && START + RANGE <= LENGTH) */
+
+static reg_errcode_t
+re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch,
+ eflags)
+ const regex_t *preg;
+ const char *string;
+ int length, start, range, stop, eflags;
+ size_t nmatch;
+ regmatch_t pmatch[];
+{
+ reg_errcode_t err;
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int left_lim, right_lim, incr;
+ int fl_longest_match, match_first, match_kind, match_last = -1;
+ int extra_nmatch;
+ int sb, ch;
+#if defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
+ re_match_context_t mctx = { .dfa = dfa };
+#else
+ re_match_context_t mctx;
+#endif
+ char *fastmap = (preg->fastmap != NULL && preg->fastmap_accurate
+ && range && !preg->can_be_null) ? preg->fastmap : NULL;
+ RE_TRANSLATE_TYPE t = preg->translate;
+
+#if !(defined _LIBC || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L))
+ memset (&mctx, '\0', sizeof (re_match_context_t));
+ mctx.dfa = dfa;
+#endif
+
+ extra_nmatch = (nmatch > preg->re_nsub) ? nmatch - (preg->re_nsub + 1) : 0;
+ nmatch -= extra_nmatch;
+
+ /* Check if the DFA haven't been compiled. */
+ if (BE (preg->used == 0 || dfa->init_state == NULL
+ || dfa->init_state_word == NULL || dfa->init_state_nl == NULL
+ || dfa->init_state_begbuf == NULL, 0))
+ return REG_NOMATCH;
+
+#ifdef DEBUG
+ /* We assume front-end functions already check them. */
+ assert (start + range >= 0 && start + range <= length);
+#endif
+
+ /* If initial states with non-begbuf contexts have no elements,
+ the regex must be anchored. If preg->newline_anchor is set,
+ we'll never use init_state_nl, so do not check it. */
+ if (dfa->init_state->nodes.nelem == 0
+ && dfa->init_state_word->nodes.nelem == 0
+ && (dfa->init_state_nl->nodes.nelem == 0
+ || !preg->newline_anchor))
+ {
+ if (start != 0 && start + range != 0)
+ return REG_NOMATCH;
+ start = range = 0;
+ }
+
+ /* We must check the longest matching, if nmatch > 0. */
+ fl_longest_match = (nmatch != 0 || dfa->nbackref);
+
+ err = re_string_allocate (&mctx.input, string, length, dfa->nodes_len + 1,
+ preg->translate, preg->syntax & RE_ICASE, dfa);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ mctx.input.stop = stop;
+ mctx.input.raw_stop = stop;
+ mctx.input.newline_anchor = preg->newline_anchor;
+
+ err = match_ctx_init (&mctx, eflags, dfa->nbackref * 2);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* We will log all the DFA states through which the dfa pass,
+ if nmatch > 1, or this dfa has "multibyte node", which is a
+ back-reference or a node which can accept multibyte character or
+ multi character collating element. */
+ if (nmatch > 1 || dfa->has_mb_node)
+ {
+ mctx.state_log = re_malloc (re_dfastate_t *, mctx.input.bufs_len + 1);
+ if (BE (mctx.state_log == NULL, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ }
+ else
+ mctx.state_log = NULL;
+
+ match_first = start;
+ mctx.input.tip_context = (eflags & REG_NOTBOL) ? CONTEXT_BEGBUF
+ : CONTEXT_NEWLINE | CONTEXT_BEGBUF;
+
+ /* Check incrementally whether of not the input string match. */
+ incr = (range < 0) ? -1 : 1;
+ left_lim = (range < 0) ? start + range : start;
+ right_lim = (range < 0) ? start : start + range;
+ sb = dfa->mb_cur_max == 1;
+ match_kind =
+ (fastmap
+ ? ((sb || !(preg->syntax & RE_ICASE || t) ? 4 : 0)
+ | (range >= 0 ? 2 : 0)
+ | (t != NULL ? 1 : 0))
+ : 8);
+
+ for (;; match_first += incr)
+ {
+ err = REG_NOMATCH;
+ if (match_first < left_lim || right_lim < match_first)
+ goto free_return;
+
+ /* Advance as rapidly as possible through the string, until we
+ find a plausible place to start matching. This may be done
+ with varying efficiency, so there are various possibilities:
+ only the most common of them are specialized, in order to
+ save on code size. We use a switch statement for speed. */
+ switch (match_kind)
+ {
+ case 8:
+ /* No fastmap. */
+ break;
+
+ case 7:
+ /* Fastmap with single-byte translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[t[(unsigned char) string[match_first]]])
+ ++match_first;
+ goto forward_match_found_start_or_reached_end;
+
+ case 6:
+ /* Fastmap without translation, match forward. */
+ while (BE (match_first < right_lim, 1)
+ && !fastmap[(unsigned char) string[match_first]])
+ ++match_first;
+
+ forward_match_found_start_or_reached_end:
+ if (BE (match_first == right_lim, 0))
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (!fastmap[t ? t[ch] : ch])
+ goto free_return;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Fastmap without multi-byte translation, match backwards. */
+ while (match_first >= left_lim)
+ {
+ ch = match_first >= length
+ ? 0 : (unsigned char) string[match_first];
+ if (fastmap[t ? t[ch] : ch])
+ break;
+ --match_first;
+ }
+ if (match_first < left_lim)
+ goto free_return;
+ break;
+
+ default:
+ /* In this case, we can't determine easily the current byte,
+ since it might be a component byte of a multibyte
+ character. Then we use the constructed buffer instead. */
+ for (;;)
+ {
+ /* If MATCH_FIRST is out of the valid range, reconstruct the
+ buffers. */
+ unsigned int offset = match_first - mctx.input.raw_mbs_idx;
+ if (BE (offset >= (unsigned int) mctx.input.valid_raw_len, 0))
+ {
+ err = re_string_reconstruct (&mctx.input, match_first,
+ eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ offset = match_first - mctx.input.raw_mbs_idx;
+ }
+ /* If MATCH_FIRST is out of the buffer, leave it as '\0'.
+ Note that MATCH_FIRST must not be smaller than 0. */
+ ch = (match_first >= length
+ ? 0 : re_string_byte_at (&mctx.input, offset));
+ if (fastmap[ch])
+ break;
+ match_first += incr;
+ if (match_first < left_lim || match_first > right_lim)
+ {
+ err = REG_NOMATCH;
+ goto free_return;
+ }
+ }
+ break;
+ }
+
+ /* Reconstruct the buffers so that the matcher can assume that
+ the matching starts from the beginning of the buffer. */
+ err = re_string_reconstruct (&mctx.input, match_first, eflags);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+#ifdef RE_ENABLE_I18N
+ /* Don't consider this char as a possible match start if it part,
+ yet isn't the head, of a multibyte character. */
+ if (!sb && !re_string_first_byte (&mctx.input, 0))
+ continue;
+#endif
+
+ /* It seems to be appropriate one, then use the matcher. */
+ /* We assume that the matching starts from 0. */
+ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0;
+ match_last = check_matching (&mctx, fl_longest_match,
+ range >= 0 ? &match_first : NULL);
+ if (match_last != -1)
+ {
+ if (BE (match_last == -2, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ else
+ {
+ mctx.match_last = match_last;
+ if ((!preg->no_sub && nmatch > 1) || dfa->nbackref)
+ {
+ re_dfastate_t *pstate = mctx.state_log[match_last];
+ mctx.last_node = check_halt_state_context (&mctx, pstate,
+ match_last);
+ }
+ if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match)
+ || dfa->nbackref)
+ {
+ err = prune_impossible_nodes (&mctx);
+ if (err == REG_NOERROR)
+ break;
+ if (BE (err != REG_NOMATCH, 0))
+ goto free_return;
+ match_last = -1;
+ }
+ else
+ break; /* We found a match. */
+ }
+ }
+
+ match_ctx_clean (&mctx);
+ }
+
+#ifdef DEBUG
+ assert (match_last != -1);
+ assert (err == REG_NOERROR);
+#endif
+
+ /* Set pmatch[] if we need. */
+ if (nmatch > 0)
+ {
+ int reg_idx;
+
+ /* Initialize registers. */
+ for (reg_idx = 1; reg_idx < nmatch; ++reg_idx)
+ pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1;
+
+ /* Set the points where matching start/end. */
+ pmatch[0].rm_so = 0;
+ pmatch[0].rm_eo = mctx.match_last;
+
+ if (!preg->no_sub && nmatch > 1)
+ {
+ err = set_regs (preg, &mctx, nmatch, pmatch,
+ dfa->has_plural_match && dfa->nbackref > 0);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* At last, add the offset to the each registers, since we slided
+ the buffers so that we could assume that the matching starts
+ from 0. */
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so != -1)
+ {
+#ifdef RE_ENABLE_I18N
+ if (BE (mctx.input.offsets_needed != 0, 0))
+ {
+ pmatch[reg_idx].rm_so =
+ (pmatch[reg_idx].rm_so == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_so]);
+ pmatch[reg_idx].rm_eo =
+ (pmatch[reg_idx].rm_eo == mctx.input.valid_len
+ ? mctx.input.valid_raw_len
+ : mctx.input.offsets[pmatch[reg_idx].rm_eo]);
+ }
+#else
+ assert (mctx.input.offsets_needed == 0);
+#endif
+ pmatch[reg_idx].rm_so += match_first;
+ pmatch[reg_idx].rm_eo += match_first;
+ }
+ for (reg_idx = 0; reg_idx < extra_nmatch; ++reg_idx)
+ {
+ pmatch[nmatch + reg_idx].rm_so = -1;
+ pmatch[nmatch + reg_idx].rm_eo = -1;
+ }
+
+ if (dfa->subexp_map)
+ for (reg_idx = 0; reg_idx + 1 < nmatch; reg_idx++)
+ if (dfa->subexp_map[reg_idx] != reg_idx)
+ {
+ pmatch[reg_idx + 1].rm_so
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_so;
+ pmatch[reg_idx + 1].rm_eo
+ = pmatch[dfa->subexp_map[reg_idx] + 1].rm_eo;
+ }
+ }
+
+ free_return:
+ re_free (mctx.state_log);
+ if (dfa->nbackref)
+ match_ctx_free (&mctx);
+ re_string_destruct (&mctx.input);
+ return err;
+}
+
+static reg_errcode_t
+prune_impossible_nodes (mctx)
+ re_match_context_t *mctx;
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int halt_node, match_last;
+ reg_errcode_t ret;
+ re_dfastate_t **sifted_states;
+ re_dfastate_t **lim_states = NULL;
+ re_sift_context_t sctx;
+#ifdef DEBUG
+ assert (mctx->state_log != NULL);
+#endif
+ match_last = mctx->match_last;
+ halt_node = mctx->last_node;
+ sifted_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (sifted_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ if (dfa->nbackref)
+ {
+ lim_states = re_malloc (re_dfastate_t *, match_last + 1);
+ if (BE (lim_states == NULL, 0))
+ {
+ ret = REG_ESPACE;
+ goto free_return;
+ }
+ while (1)
+ {
+ memset (lim_states, '\0',
+ sizeof (re_dfastate_t *) * (match_last + 1));
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node,
+ match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ if (sifted_states[0] != NULL || lim_states[0] != NULL)
+ break;
+ do
+ {
+ --match_last;
+ if (match_last < 0)
+ {
+ ret = REG_NOMATCH;
+ goto free_return;
+ }
+ } while (mctx->state_log[match_last] == NULL
+ || !mctx->state_log[match_last]->halt);
+ halt_node = check_halt_state_context (mctx,
+ mctx->state_log[match_last],
+ match_last);
+ }
+ ret = merge_state_array (dfa, sifted_states, lim_states,
+ match_last + 1);
+ re_free (lim_states);
+ lim_states = NULL;
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last);
+ ret = sift_states_backward (mctx, &sctx);
+ re_node_set_free (&sctx.limits);
+ if (BE (ret != REG_NOERROR, 0))
+ goto free_return;
+ }
+ re_free (mctx->state_log);
+ mctx->state_log = sifted_states;
+ sifted_states = NULL;
+ mctx->last_node = halt_node;
+ mctx->match_last = match_last;
+ ret = REG_NOERROR;
+ free_return:
+ re_free (sifted_states);
+ re_free (lim_states);
+ return ret;
+}
+
+/* Acquire an initial state and return it.
+ We must select appropriate initial state depending on the context,
+ since initial states may have constraints like "\<", "^", etc.. */
+
+static inline re_dfastate_t *
+__attribute ((always_inline)) internal_function
+acquire_init_state_context (reg_errcode_t *err, const re_match_context_t *mctx,
+ int idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ if (dfa->init_state->has_constraint)
+ {
+ unsigned int context;
+ context = re_string_context_at (&mctx->input, idx - 1, mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return dfa->init_state_word;
+ else if (IS_ORDINARY_CONTEXT (context))
+ return dfa->init_state;
+ else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_begbuf;
+ else if (IS_NEWLINE_CONTEXT (context))
+ return dfa->init_state_nl;
+ else if (IS_BEGBUF_CONTEXT (context))
+ {
+ /* It is relatively rare case, then calculate on demand. */
+ return re_acquire_state_context (err, dfa,
+ dfa->init_state->entrance_nodes,
+ context);
+ }
+ else
+ /* Must not happen? */
+ return dfa->init_state;
+ }
+ else
+ return dfa->init_state;
+}
+
+/* Check whether the regular expression match input string INPUT or not,
+ and return the index where the matching end, return -1 if not match,
+ or return -2 in case of an error.
+ FL_LONGEST_MATCH means we want the POSIX longest matching.
+ If P_MATCH_FIRST is not NULL, and the match fails, it is set to the
+ next place where we may want to try matching.
+ Note that the matcher assume that the maching starts from the current
+ index of the buffer. */
+
+static int
+internal_function
+check_matching (re_match_context_t *mctx, int fl_longest_match,
+ int *p_match_first)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int match = 0;
+ int match_last = -1;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+ re_dfastate_t *cur_state;
+ int at_init_state = p_match_first != NULL;
+ int next_start_idx = cur_str_idx;
+
+ err = REG_NOERROR;
+ cur_state = acquire_init_state_context (&err, mctx, cur_str_idx);
+ /* An initial state must not be NULL (invalid). */
+ if (BE (cur_state == NULL, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+
+ if (mctx->state_log != NULL)
+ {
+ mctx->state_log[cur_str_idx] = cur_state;
+
+ /* Check OP_OPEN_SUBEXP in the initial state in case that we use them
+ later. E.g. Processing back references. */
+ if (BE (dfa->nbackref, 0))
+ {
+ at_init_state = 0;
+ err = check_subexp_matching_top (mctx, &cur_state->nodes, 0);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (cur_state->has_backref)
+ {
+ err = transit_state_bkref (mctx, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+
+ /* If the RE accepts NULL string. */
+ if (BE (cur_state->halt, 0))
+ {
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state, cur_str_idx))
+ {
+ if (!fl_longest_match)
+ return cur_str_idx;
+ else
+ {
+ match_last = cur_str_idx;
+ match = 1;
+ }
+ }
+ }
+
+ while (!re_string_eoi (&mctx->input))
+ {
+ re_dfastate_t *old_state = cur_state;
+ int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
+
+ if (BE (next_char_idx >= mctx->input.bufs_len, 0)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ assert (err == REG_ESPACE);
+ return -2;
+ }
+ }
+
+ cur_state = transit_state (&err, mctx, cur_state);
+ if (mctx->state_log != NULL)
+ cur_state = merge_state_with_log (&err, mctx, cur_state);
+
+ if (cur_state == NULL)
+ {
+ /* Reached the invalid state or an error. Try to recover a valid
+ state using the state log, if available and if we have not
+ already found a valid (even if not the longest) match. */
+ if (BE (err != REG_NOERROR, 0))
+ return -2;
+
+ if (mctx->state_log == NULL
+ || (match && !fl_longest_match)
+ || (cur_state = find_recover_state (&err, mctx)) == NULL)
+ break;
+ }
+
+ if (BE (at_init_state, 0))
+ {
+ if (old_state == cur_state)
+ next_start_idx = next_char_idx;
+ else
+ at_init_state = 0;
+ }
+
+ if (cur_state->halt)
+ {
+ /* Reached a halt state.
+ Check the halt state can satisfy the current context. */
+ if (!cur_state->has_constraint
+ || check_halt_state_context (mctx, cur_state,
+ re_string_cur_idx (&mctx->input)))
+ {
+ /* We found an appropriate halt state. */
+ match_last = re_string_cur_idx (&mctx->input);
+ match = 1;
+
+ /* We found a match, do not modify match_first below. */
+ p_match_first = NULL;
+ if (!fl_longest_match)
+ break;
+ }
+ }
+ }
+
+ if (p_match_first)
+ *p_match_first += next_start_idx;
+
+ return match_last;
+}
+
+/* Check NODE match the current context. */
+
+static int
+internal_function
+check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context)
+{
+ re_token_type_t type = dfa->nodes[node].type;
+ unsigned int constraint = dfa->nodes[node].constraint;
+ if (type != END_OF_RE)
+ return 0;
+ if (!constraint)
+ return 1;
+ if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context))
+ return 0;
+ return 1;
+}
+
+/* Check the halt state STATE match the current context.
+ Return 0 if not match, if the node, STATE has, is a halt node and
+ match the context, return the node. */
+
+static int
+internal_function
+check_halt_state_context (const re_match_context_t *mctx,
+ const re_dfastate_t *state, int idx)
+{
+ int i;
+ unsigned int context;
+#ifdef DEBUG
+ assert (state->halt);
+#endif
+ context = re_string_context_at (&mctx->input, idx, mctx->eflags);
+ for (i = 0; i < state->nodes.nelem; ++i)
+ if (check_halt_node_context (mctx->dfa, state->nodes.elems[i], context))
+ return state->nodes.elems[i];
+ return 0;
+}
+
+/* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA
+ corresponding to the DFA).
+ Return the destination node, and update EPS_VIA_NODES, return -1 in case
+ of errors. */
+
+static int
+internal_function
+proceed_next_node (const re_match_context_t *mctx, int nregs, regmatch_t *regs,
+ int *pidx, int node, re_node_set *eps_via_nodes,
+ struct re_fail_stack_t *fs)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int i, err;
+ if (IS_EPSILON_NODE (dfa->nodes[node].type))
+ {
+ re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes;
+ re_node_set *edests = &dfa->edests[node];
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ /* Pick up a valid destination, or return -1 if none is found. */
+ for (dest_node = -1, i = 0; i < edests->nelem; ++i)
+ {
+ int candidate = edests->elems[i];
+ if (!re_node_set_contains (cur_nodes, candidate))
+ continue;
+ if (dest_node == -1)
+ dest_node = candidate;
+
+ else
+ {
+ /* In order to avoid infinite loop like "(a*)*", return the second
+ epsilon-transition if the first was already considered. */
+ if (re_node_set_contains (eps_via_nodes, dest_node))
+ return candidate;
+
+ /* Otherwise, push the second epsilon-transition on the fail stack. */
+ else if (fs != NULL
+ && push_fail_stack (fs, *pidx, candidate, nregs, regs,
+ eps_via_nodes))
+ return -2;
+
+ /* We know we are going to exit. */
+ break;
+ }
+ }
+ return dest_node;
+ }
+ else
+ {
+ int naccepted = 0;
+ re_token_type_t type = dfa->nodes[node].type;
+
+#ifdef RE_ENABLE_I18N
+ if (dfa->nodes[node].accept_mb)
+ naccepted = check_node_accept_bytes (dfa, node, &mctx->input, *pidx);
+ else
+#endif /* RE_ENABLE_I18N */
+ if (type == OP_BACK_REF)
+ {
+ int subexp_idx = dfa->nodes[node].opr.idx + 1;
+ naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so;
+ if (fs != NULL)
+ {
+ if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1)
+ return -1;
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+ if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+ naccepted) != 0)
+ return -1;
+ }
+ }
+
+ if (naccepted == 0)
+ {
+ int dest_node;
+ err = re_node_set_insert (eps_via_nodes, node);
+ if (BE (err < 0, 0))
+ return -2;
+ dest_node = dfa->edests[node].elems[0];
+ if (re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node))
+ return dest_node;
+ }
+ }
+
+ if (naccepted != 0
+ || check_node_accept (mctx, dfa->nodes + node, *pidx))
+ {
+ int dest_node = dfa->nexts[node];
+ *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted;
+ if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL
+ || !re_node_set_contains (&mctx->state_log[*pidx]->nodes,
+ dest_node)))
+ return -1;
+ re_node_set_empty (eps_via_nodes);
+ return dest_node;
+ }
+ }
+ return -1;
+}
+
+static reg_errcode_t
+internal_function
+push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int dest_node,
+ int nregs, regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ reg_errcode_t err;
+ int num = fs->num++;
+ if (fs->num == fs->alloc)
+ {
+ struct re_fail_stack_ent_t *new_array;
+ new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t)
+ * fs->alloc * 2));
+ if (new_array == NULL)
+ return REG_ESPACE;
+ fs->alloc *= 2;
+ fs->stack = new_array;
+ }
+ fs->stack[num].idx = str_idx;
+ fs->stack[num].node = dest_node;
+ fs->stack[num].regs = re_malloc (regmatch_t, nregs);
+ if (fs->stack[num].regs == NULL)
+ return REG_ESPACE;
+ memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs);
+ err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes);
+ return err;
+}
+
+static int
+internal_function
+pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs,
+ regmatch_t *regs, re_node_set *eps_via_nodes)
+{
+ int num = --fs->num;
+ assert (num >= 0);
+ *pidx = fs->stack[num].idx;
+ memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs);
+ re_node_set_free (eps_via_nodes);
+ re_free (fs->stack[num].regs);
+ *eps_via_nodes = fs->stack[num].eps_via_nodes;
+ return fs->stack[num].node;
+}
+
+/* Set the positions where the subexpressions are starts/ends to registers
+ PMATCH.
+ Note: We assume that pmatch[0] is already set, and
+ pmatch[i].rm_so == pmatch[i].rm_eo == -1 for 0 < i < nmatch. */
+
+static reg_errcode_t
+internal_function
+set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch,
+ regmatch_t *pmatch, int fl_backtrack)
+{
+ const re_dfa_t *dfa = (const re_dfa_t *) preg->buffer;
+ int idx, cur_node;
+ re_node_set eps_via_nodes;
+ struct re_fail_stack_t *fs;
+ struct re_fail_stack_t fs_body = { 0, 2, NULL };
+ regmatch_t *prev_idx_match;
+ int prev_idx_match_malloced = 0;
+
+#ifdef DEBUG
+ assert (nmatch > 1);
+ assert (mctx->state_log != NULL);
+#endif
+ if (fl_backtrack)
+ {
+ fs = &fs_body;
+ fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc);
+ if (fs->stack == NULL)
+ return REG_ESPACE;
+ }
+ else
+ fs = NULL;
+
+ cur_node = dfa->init_node;
+ re_node_set_init_empty (&eps_via_nodes);
+
+ if (__libc_use_alloca (nmatch * sizeof (regmatch_t)))
+ prev_idx_match = (regmatch_t *) alloca (nmatch * sizeof (regmatch_t));
+ else
+ {
+ prev_idx_match = re_malloc (regmatch_t, nmatch);
+ if (prev_idx_match == NULL)
+ {
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ prev_idx_match_malloced = 1;
+ }
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+
+ for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;)
+ {
+ update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, nmatch);
+
+ if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node)
+ {
+ int reg_idx;
+ if (fs)
+ {
+ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx)
+ if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1)
+ break;
+ if (reg_idx == nmatch)
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+ }
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ }
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOERROR;
+ }
+ }
+
+ /* Proceed to next node. */
+ cur_node = proceed_next_node (mctx, nmatch, pmatch, &idx, cur_node,
+ &eps_via_nodes, fs);
+
+ if (BE (cur_node < 0, 0))
+ {
+ if (BE (cur_node == -2, 0))
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ free_fail_stack_return (fs);
+ return REG_ESPACE;
+ }
+ if (fs)
+ cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch,
+ &eps_via_nodes);
+ else
+ {
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return REG_NOMATCH;
+ }
+ }
+ }
+ re_node_set_free (&eps_via_nodes);
+ if (prev_idx_match_malloced)
+ re_free (prev_idx_match);
+ return free_fail_stack_return (fs);
+}
+
+static reg_errcode_t
+internal_function
+free_fail_stack_return (struct re_fail_stack_t *fs)
+{
+ if (fs)
+ {
+ int fs_idx;
+ for (fs_idx = 0; fs_idx < fs->num; ++fs_idx)
+ {
+ re_node_set_free (&fs->stack[fs_idx].eps_via_nodes);
+ re_free (fs->stack[fs_idx].regs);
+ }
+ re_free (fs->stack);
+ }
+ return REG_NOERROR;
+}
+
+static void
+internal_function
+update_regs (const re_dfa_t *dfa, regmatch_t *pmatch,
+ regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch)
+{
+ int type = dfa->nodes[cur_node].type;
+ if (type == OP_OPEN_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+
+ /* We are at the first node of this sub expression. */
+ if (reg_num < nmatch)
+ {
+ pmatch[reg_num].rm_so = cur_idx;
+ pmatch[reg_num].rm_eo = -1;
+ }
+ }
+ else if (type == OP_CLOSE_SUBEXP)
+ {
+ int reg_num = dfa->nodes[cur_node].opr.idx + 1;
+ if (reg_num < nmatch)
+ {
+ /* We are at the last node of this sub expression. */
+ if (pmatch[reg_num].rm_so < cur_idx)
+ {
+ pmatch[reg_num].rm_eo = cur_idx;
+ /* This is a non-empty match or we are not inside an optional
+ subexpression. Accept this right away. */
+ memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch);
+ }
+ else
+ {
+ if (dfa->nodes[cur_node].opt_subexp
+ && prev_idx_match[reg_num].rm_so != -1)
+ /* We transited through an empty match for an optional
+ subexpression, like (a?)*, and this is not the subexp's
+ first match. Copy back the old content of the registers
+ so that matches of an inner subexpression are undone as
+ well, like in ((a?))*. */
+ memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch);
+ else
+ /* We completed a subexpression, but it may be part of
+ an optional one, so do not update PREV_IDX_MATCH. */
+ pmatch[reg_num].rm_eo = cur_idx;
+ }
+ }
+ }
+}
+
+/* This function checks the STATE_LOG from the SCTX->last_str_idx to 0
+ and sift the nodes in each states according to the following rules.
+ Updated state_log will be wrote to STATE_LOG.
+
+ Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if...
+ 1. When STR_IDX == MATCH_LAST(the last index in the state_log):
+ If `a' isn't the LAST_NODE and `a' can't epsilon transit to
+ the LAST_NODE, we throw away the node `a'.
+ 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts
+ string `s' and transit to `b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw
+ away the node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is
+ thrown away, we throw away the node `a'.
+ 3. When 0 <= STR_IDX < MATCH_LAST and 'a' epsilon transit to 'b':
+ i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the
+ node `a'.
+ ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is thrown away,
+ we throw away the node `a'. */
+
+#define STATE_NODE_CONTAINS(state,node) \
+ ((state) != NULL && re_node_set_contains (&(state)->nodes, node))
+
+static reg_errcode_t
+internal_function
+sift_states_backward (const re_match_context_t *mctx, re_sift_context_t *sctx)
+{
+ reg_errcode_t err;
+ int null_cnt = 0;
+ int str_idx = sctx->last_str_idx;
+ re_node_set cur_dest;
+
+#ifdef DEBUG
+ assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL);
+#endif
+
+ /* Build sifted state_log[str_idx]. It has the nodes which can epsilon
+ transit to the last_node and the last_node itself. */
+ err = re_node_set_init_1 (&cur_dest, sctx->last_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* Then check each states in the state_log. */
+ while (str_idx > 0)
+ {
+ /* Update counters. */
+ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0;
+ if (null_cnt > mctx->max_mb_elem_len)
+ {
+ memset (sctx->sifted_states, '\0',
+ sizeof (re_dfastate_t *) * str_idx);
+ re_node_set_free (&cur_dest);
+ return REG_NOERROR;
+ }
+ re_node_set_empty (&cur_dest);
+ --str_idx;
+
+ if (mctx->state_log[str_idx])
+ {
+ err = build_sifted_states (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+
+ /* Add all the nodes which satisfy the following conditions:
+ - It can epsilon transit to a node in CUR_DEST.
+ - It is in CUR_SRC.
+ And update state_log. */
+ err = update_cur_sifted_state (mctx, sctx, str_idx, &cur_dest);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ err = REG_NOERROR;
+ free_return:
+ re_node_set_free (&cur_dest);
+ return err;
+}
+
+static reg_errcode_t
+internal_function
+build_sifted_states (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, re_node_set *cur_dest)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *cur_src = &mctx->state_log[str_idx]->non_eps_nodes;
+ int i;
+
+ /* Then build the next sifted state.
+ We build the next sifted state on `cur_dest', and update
+ `sifted_states[str_idx]' with `cur_dest'.
+ Note:
+ `cur_dest' is the sifted state from `state_log[str_idx + 1]'.
+ `cur_src' points the node_set of the old `state_log[str_idx]'
+ (with the epsilon nodes pre-filtered out). */
+ for (i = 0; i < cur_src->nelem; i++)
+ {
+ int prev_node = cur_src->elems[i];
+ int naccepted = 0;
+ int ret;
+
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[prev_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[prev_node].accept_mb)
+ naccepted = sift_states_iter_mb (mctx, sctx, prev_node,
+ str_idx, sctx->last_str_idx);
+#endif /* RE_ENABLE_I18N */
+
+ /* We don't check backreferences here.
+ See update_cur_sifted_state(). */
+ if (!naccepted
+ && check_node_accept (mctx, dfa->nodes + prev_node, str_idx)
+ && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1],
+ dfa->nexts[prev_node]))
+ naccepted = 1;
+
+ if (naccepted == 0)
+ continue;
+
+ if (sctx->limits.nelem)
+ {
+ int to_idx = str_idx + naccepted;
+ if (check_dst_limits (mctx, &sctx->limits,
+ dfa->nexts[prev_node], to_idx,
+ prev_node, str_idx))
+ continue;
+ }
+ ret = re_node_set_insert (cur_dest, prev_node);
+ if (BE (ret == -1, 0))
+ return REG_ESPACE;
+ }
+
+ return REG_NOERROR;
+}
+
+/* Helper functions. */
+
+static reg_errcode_t
+internal_function
+clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
+{
+ int top = mctx->state_log_top;
+
+ if (next_state_log_idx >= mctx->input.bufs_len
+ || (next_state_log_idx >= mctx->input.valid_len
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ reg_errcode_t err;
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (top < next_state_log_idx)
+ {
+ memset (mctx->state_log + top + 1, '\0',
+ sizeof (re_dfastate_t *) * (next_state_log_idx - top));
+ mctx->state_log_top = next_state_log_idx;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+merge_state_array (const re_dfa_t *dfa, re_dfastate_t **dst,
+ re_dfastate_t **src, int num)
+{
+ int st_idx;
+ reg_errcode_t err;
+ for (st_idx = 0; st_idx < num; ++st_idx)
+ {
+ if (dst[st_idx] == NULL)
+ dst[st_idx] = src[st_idx];
+ else if (src[st_idx] != NULL)
+ {
+ re_node_set merged_set;
+ err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes,
+ &src[st_idx]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ dst[st_idx] = re_acquire_state (&err, dfa, &merged_set);
+ re_node_set_free (&merged_set);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+update_cur_sifted_state (const re_match_context_t *mctx,
+ re_sift_context_t *sctx, int str_idx,
+ re_node_set *dest_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ const re_node_set *candidates;
+ candidates = ((mctx->state_log[str_idx] == NULL) ? NULL
+ : &mctx->state_log[str_idx]->nodes);
+
+ if (dest_nodes->nelem == 0)
+ sctx->sifted_states[str_idx] = NULL;
+ else
+ {
+ if (candidates)
+ {
+ /* At first, add the nodes which can epsilon transit to a node in
+ DEST_NODE. */
+ err = add_epsilon_src_nodes (dfa, dest_nodes, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ /* Then, check the limitations in the current sift_context. */
+ if (sctx->limits.nelem)
+ {
+ err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits,
+ mctx->bkref_ents, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+
+ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (candidates && mctx->state_log[str_idx]->has_backref)
+ {
+ err = sift_states_bkref (mctx, sctx, str_idx, candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+add_epsilon_src_nodes (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ reg_errcode_t err = REG_NOERROR;
+ int i;
+
+ re_dfastate_t *state = re_acquire_state (&err, dfa, dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ if (!state->inveclosure.alloc)
+ {
+ err = re_node_set_alloc (&state->inveclosure, dest_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return REG_ESPACE;
+ for (i = 0; i < dest_nodes->nelem; i++)
+ re_node_set_merge (&state->inveclosure,
+ dfa->inveclosures + dest_nodes->elems[i]);
+ }
+ return re_node_set_add_intersect (dest_nodes, candidates,
+ &state->inveclosure);
+}
+
+static reg_errcode_t
+internal_function
+sub_epsilon_src_nodes (const re_dfa_t *dfa, int node, re_node_set *dest_nodes,
+ const re_node_set *candidates)
+{
+ int ecl_idx;
+ reg_errcode_t err;
+ re_node_set *inv_eclosure = dfa->inveclosures + node;
+ re_node_set except_nodes;
+ re_node_set_init_empty (&except_nodes);
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (cur_node == node)
+ continue;
+ if (IS_EPSILON_NODE (dfa->nodes[cur_node].type))
+ {
+ int edst1 = dfa->edests[cur_node].elems[0];
+ int edst2 = ((dfa->edests[cur_node].nelem > 1)
+ ? dfa->edests[cur_node].elems[1] : -1);
+ if ((!re_node_set_contains (inv_eclosure, edst1)
+ && re_node_set_contains (dest_nodes, edst1))
+ || (edst2 > 0
+ && !re_node_set_contains (inv_eclosure, edst2)
+ && re_node_set_contains (dest_nodes, edst2)))
+ {
+ err = re_node_set_add_intersect (&except_nodes, candidates,
+ dfa->inveclosures + cur_node);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&except_nodes);
+ return err;
+ }
+ }
+ }
+ }
+ for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx)
+ {
+ int cur_node = inv_eclosure->elems[ecl_idx];
+ if (!re_node_set_contains (&except_nodes, cur_node))
+ {
+ int idx = re_node_set_contains (dest_nodes, cur_node) - 1;
+ re_node_set_remove_at (dest_nodes, idx);
+ }
+ }
+ re_node_set_free (&except_nodes);
+ return REG_NOERROR;
+}
+
+static int
+internal_function
+check_dst_limits (const re_match_context_t *mctx, re_node_set *limits,
+ int dst_node, int dst_idx, int src_node, int src_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int lim_idx, src_pos, dst_pos;
+
+ int dst_bkref_idx = search_cur_bkref_entry (mctx, dst_idx);
+ int src_bkref_idx = search_cur_bkref_entry (mctx, src_idx);
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = mctx->bkref_ents + limits->elems[lim_idx];
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+
+ dst_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, dst_node, dst_idx,
+ dst_bkref_idx);
+ src_pos = check_dst_limits_calc_pos (mctx, limits->elems[lim_idx],
+ subexp_idx, src_node, src_idx,
+ src_bkref_idx);
+
+ /* In case of:
+ <src> <dst> ( <subexp> )
+ ( <subexp> ) <src> <dst>
+ ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */
+ if (src_pos == dst_pos)
+ continue; /* This is unrelated limitation. */
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos_1 (const re_match_context_t *mctx, int boundaries,
+ int subexp_idx, int from_node, int bkref_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ const re_node_set *eclosures = dfa->eclosures + from_node;
+ int node_idx;
+
+ /* Else, we are on the boundary: examine the nodes on the epsilon
+ closure. */
+ for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx)
+ {
+ int node = eclosures->elems[node_idx];
+ switch (dfa->nodes[node].type)
+ {
+ case OP_BACK_REF:
+ if (bkref_idx != -1)
+ {
+ struct re_backref_cache_entry *ent = mctx->bkref_ents + bkref_idx;
+ do
+ {
+ int dst, cpos;
+
+ if (ent->node != node)
+ continue;
+
+ if (subexp_idx < BITSET_WORD_BITS
+ && !(ent->eps_reachable_subexps_map
+ & ((bitset_word_t) 1 << subexp_idx)))
+ continue;
+
+ /* Recurse trying to reach the OP_OPEN_SUBEXP and
+ OP_CLOSE_SUBEXP cases below. But, if the
+ destination node is the same node as the source
+ node, don't recurse because it would cause an
+ infinite loop: a regex that exhibits this behavior
+ is ()\1*\1* */
+ dst = dfa->edests[node].elems[0];
+ if (dst == from_node)
+ {
+ if (boundaries & 1)
+ return -1;
+ else /* if (boundaries & 2) */
+ return 0;
+ }
+
+ cpos =
+ check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ dst, bkref_idx);
+ if (cpos == -1 /* && (boundaries & 1) */)
+ return -1;
+ if (cpos == 0 && (boundaries & 2))
+ return 0;
+
+ if (subexp_idx < BITSET_WORD_BITS)
+ ent->eps_reachable_subexps_map
+ &= ~((bitset_word_t) 1 << subexp_idx);
+ }
+ while (ent++->more);
+ }
+ break;
+
+ case OP_OPEN_SUBEXP:
+ if ((boundaries & 1) && subexp_idx == dfa->nodes[node].opr.idx)
+ return -1;
+ break;
+
+ case OP_CLOSE_SUBEXP:
+ if ((boundaries & 2) && subexp_idx == dfa->nodes[node].opr.idx)
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return (boundaries & 2) ? 1 : 0;
+}
+
+static int
+internal_function
+check_dst_limits_calc_pos (const re_match_context_t *mctx, int limit,
+ int subexp_idx, int from_node, int str_idx,
+ int bkref_idx)
+{
+ struct re_backref_cache_entry *lim = mctx->bkref_ents + limit;
+ int boundaries;
+
+ /* If we are outside the range of the subexpression, return -1 or 1. */
+ if (str_idx < lim->subexp_from)
+ return -1;
+
+ if (lim->subexp_to < str_idx)
+ return 1;
+
+ /* If we are within the subexpression, return 0. */
+ boundaries = (str_idx == lim->subexp_from);
+ boundaries |= (str_idx == lim->subexp_to) << 1;
+ if (boundaries == 0)
+ return 0;
+
+ /* Else, examine epsilon closure. */
+ return check_dst_limits_calc_pos_1 (mctx, boundaries, subexp_idx,
+ from_node, bkref_idx);
+}
+
+/* Check the limitations of sub expressions LIMITS, and remove the nodes
+ which are against limitations from DEST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_subexp_limits (const re_dfa_t *dfa, re_node_set *dest_nodes,
+ const re_node_set *candidates, re_node_set *limits,
+ struct re_backref_cache_entry *bkref_ents, int str_idx)
+{
+ reg_errcode_t err;
+ int node_idx, lim_idx;
+
+ for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx)
+ {
+ int subexp_idx;
+ struct re_backref_cache_entry *ent;
+ ent = bkref_ents + limits->elems[lim_idx];
+
+ if (str_idx <= ent->subexp_from || ent->str_idx < str_idx)
+ continue; /* This is unrelated limitation. */
+
+ subexp_idx = dfa->nodes[ent->node].opr.idx;
+ if (ent->subexp_to == str_idx)
+ {
+ int ops_node = -1;
+ int cls_node = -1;
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_OPEN_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ ops_node = node;
+ else if (type == OP_CLOSE_SUBEXP
+ && subexp_idx == dfa->nodes[node].opr.idx)
+ cls_node = node;
+ }
+
+ /* Check the limitation of the open subexpression. */
+ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */
+ if (ops_node >= 0)
+ {
+ err = sub_epsilon_src_nodes (dfa, ops_node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ /* Check the limitation of the close subexpression. */
+ if (cls_node >= 0)
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ if (!re_node_set_contains (dfa->inveclosures + node,
+ cls_node)
+ && !re_node_set_contains (dfa->eclosures + node,
+ cls_node))
+ {
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ --node_idx;
+ }
+ }
+ }
+ else /* (ent->subexp_to != str_idx) */
+ {
+ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx)
+ {
+ int node = dest_nodes->elems[node_idx];
+ re_token_type_t type = dfa->nodes[node].type;
+ if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP)
+ {
+ if (subexp_idx != dfa->nodes[node].opr.idx)
+ continue;
+ /* It is against this limitation.
+ Remove it form the current sifted state. */
+ err = sub_epsilon_src_nodes (dfa, node, dest_nodes,
+ candidates);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ }
+ }
+ return REG_NOERROR;
+}
+
+static reg_errcode_t
+internal_function
+sift_states_bkref (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int str_idx, const re_node_set *candidates)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int node_idx, node;
+ re_sift_context_t local_sctx;
+ int first_idx = search_cur_bkref_entry (mctx, str_idx);
+
+ if (first_idx == -1)
+ return REG_NOERROR;
+
+ local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */
+
+ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx)
+ {
+ int enabled_idx;
+ re_token_type_t type;
+ struct re_backref_cache_entry *entry;
+ node = candidates->elems[node_idx];
+ type = dfa->nodes[node].type;
+ /* Avoid infinite loop for the REs like "()\1+". */
+ if (node == sctx->last_node && str_idx == sctx->last_str_idx)
+ continue;
+ if (type != OP_BACK_REF)
+ continue;
+
+ entry = mctx->bkref_ents + first_idx;
+ enabled_idx = first_idx;
+ do
+ {
+ int subexp_len;
+ int to_idx;
+ int dst_node;
+ int ret;
+ re_dfastate_t *cur_state;
+
+ if (entry->node != node)
+ continue;
+ subexp_len = entry->subexp_to - entry->subexp_from;
+ to_idx = str_idx + subexp_len;
+ dst_node = (subexp_len ? dfa->nexts[node]
+ : dfa->edests[node].elems[0]);
+
+ if (to_idx > sctx->last_str_idx
+ || sctx->sifted_states[to_idx] == NULL
+ || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node)
+ || check_dst_limits (mctx, &sctx->limits, node,
+ str_idx, dst_node, to_idx))
+ continue;
+
+ if (local_sctx.sifted_states == NULL)
+ {
+ local_sctx = *sctx;
+ err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.last_node = node;
+ local_sctx.last_str_idx = str_idx;
+ ret = re_node_set_insert (&local_sctx.limits, enabled_idx);
+ if (BE (ret < 0, 0))
+ {
+ err = REG_ESPACE;
+ goto free_return;
+ }
+ cur_state = local_sctx.sifted_states[str_idx];
+ err = sift_states_backward (mctx, &local_sctx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ if (sctx->limited_states != NULL)
+ {
+ err = merge_state_array (dfa, sctx->limited_states,
+ local_sctx.sifted_states,
+ str_idx + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ local_sctx.sifted_states[str_idx] = cur_state;
+ re_node_set_remove (&local_sctx.limits, enabled_idx);
+
+ /* mctx->bkref_ents may have changed, reload the pointer. */
+ entry = mctx->bkref_ents + enabled_idx;
+ }
+ while (enabled_idx++, entry++->more);
+ }
+ err = REG_NOERROR;
+ free_return:
+ if (local_sctx.sifted_states != NULL)
+ {
+ re_node_set_free (&local_sctx.limits);
+ }
+
+ return err;
+}
+
+
+#ifdef RE_ENABLE_I18N
+static int
+internal_function
+sift_states_iter_mb (const re_match_context_t *mctx, re_sift_context_t *sctx,
+ int node_idx, int str_idx, int max_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int naccepted;
+ /* Check the node can accept `multi byte'. */
+ naccepted = check_node_accept_bytes (dfa, node_idx, &mctx->input, str_idx);
+ if (naccepted > 0 && str_idx + naccepted <= max_str_idx &&
+ !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted],
+ dfa->nexts[node_idx]))
+ /* The node can't accept the `multi byte', or the
+ destination was already thrown away, then the node
+ could't accept the current input `multi byte'. */
+ naccepted = 0;
+ /* Otherwise, it is sure that the node could accept
+ `naccepted' bytes input. */
+ return naccepted;
+}
+#endif /* RE_ENABLE_I18N */
+
+
+/* Functions for state transition. */
+
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte, and update STATE_LOG if necessary.
+ If STATE can accept a multibyte char/collating element/back reference
+ update the destination of STATE_LOG. */
+
+static re_dfastate_t *
+internal_function
+transit_state (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ re_dfastate_t **trtable;
+ unsigned char ch;
+
+#ifdef RE_ENABLE_I18N
+ /* If the current state can accept multibyte. */
+ if (BE (state->accept_mb, 0))
+ {
+ *err = transit_state_mb (mctx, state);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+#endif /* RE_ENABLE_I18N */
+
+ /* Then decide the next state with the single byte. */
+#if 0
+ if (0)
+ /* don't use transition table */
+ return transit_state_sb (err, mctx, state);
+#endif
+
+ /* Use transition table */
+ ch = re_string_fetch_byte (&mctx->input);
+ for (;;)
+ {
+ trtable = state->trtable;
+ if (BE (trtable != NULL, 1))
+ return trtable[ch];
+
+ trtable = state->word_trtable;
+ if (BE (trtable != NULL, 1))
+ {
+ unsigned int context;
+ context
+ = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ if (IS_WORD_CONTEXT (context))
+ return trtable[ch + SBC_MAX];
+ else
+ return trtable[ch];
+ }
+
+ if (!build_trtable (mctx->dfa, state))
+ {
+ *err = REG_ESPACE;
+ return NULL;
+ }
+
+ /* Retry, we now have a transition table. */
+ }
+}
+
+/* Update the state_log if we need */
+re_dfastate_t *
+internal_function
+merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *next_state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int cur_idx = re_string_cur_idx (&mctx->input);
+
+ if (cur_idx > mctx->state_log_top)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ mctx->state_log_top = cur_idx;
+ }
+ else if (mctx->state_log[cur_idx] == 0)
+ {
+ mctx->state_log[cur_idx] = next_state;
+ }
+ else
+ {
+ re_dfastate_t *pstate;
+ unsigned int context;
+ re_node_set next_nodes, *log_nodes, *table_nodes = NULL;
+ /* If (state_log[cur_idx] != 0), it implies that cur_idx is
+ the destination of a multibyte char/collating element/
+ back reference. Then the next state is the union set of
+ these destinations and the results of the transition table. */
+ pstate = mctx->state_log[cur_idx];
+ log_nodes = pstate->entrance_nodes;
+ if (next_state != NULL)
+ {
+ table_nodes = next_state->entrance_nodes;
+ *err = re_node_set_init_union (&next_nodes, table_nodes,
+ log_nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ }
+ else
+ next_nodes = *log_nodes;
+ /* Note: We already add the nodes of the initial state,
+ then we don't need to add them here. */
+
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input) - 1,
+ mctx->eflags);
+ next_state = mctx->state_log[cur_idx]
+ = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ if (table_nodes != NULL)
+ re_node_set_free (&next_nodes);
+ }
+
+ if (BE (dfa->nbackref, 0) && next_state != NULL)
+ {
+ /* Check OP_OPEN_SUBEXP in the current state in case that we use them
+ later. We must check them here, since the back references in the
+ next state might use them. */
+ *err = check_subexp_matching_top (mctx, &next_state->nodes,
+ cur_idx);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+
+ /* If the next state has back references. */
+ if (next_state->has_backref)
+ {
+ *err = transit_state_bkref (mctx, &next_state->nodes);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ next_state = mctx->state_log[cur_idx];
+ }
+ }
+
+ return next_state;
+}
+
+/* Skip bytes in the input that correspond to part of a
+ multi-byte match, then look in the log for a state
+ from which to restart matching. */
+re_dfastate_t *
+internal_function
+find_recover_state (reg_errcode_t *err, re_match_context_t *mctx)
+{
+ re_dfastate_t *cur_state;
+ do
+ {
+ int max = mctx->state_log_top;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ do
+ {
+ if (++cur_str_idx > max)
+ return NULL;
+ re_string_skip_bytes (&mctx->input, 1);
+ }
+ while (mctx->state_log[cur_str_idx] == NULL);
+
+ cur_state = merge_state_with_log (err, mctx, NULL);
+ }
+ while (*err == REG_NOERROR && cur_state == NULL);
+ return cur_state;
+}
+
+/* Helper functions for transit_state. */
+
+/* From the node set CUR_NODES, pick up the nodes whose types are
+ OP_OPEN_SUBEXP and which have corresponding back references in the regular
+ expression. And register them to use them later for evaluating the
+ correspoding back references. */
+
+static reg_errcode_t
+internal_function
+check_subexp_matching_top (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int node_idx;
+ reg_errcode_t err;
+
+ /* TODO: This isn't efficient.
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx)
+ {
+ int node = cur_nodes->elems[node_idx];
+ if (dfa->nodes[node].type == OP_OPEN_SUBEXP
+ && dfa->nodes[node].opr.idx < BITSET_WORD_BITS
+ && (dfa->used_bkref_map
+ & ((bitset_word_t) 1 << dfa->nodes[node].opr.idx)))
+ {
+ err = match_ctx_add_subtop (mctx, node, str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ return REG_NOERROR;
+}
+
+#if 0
+/* Return the next state to which the current state STATE will transit by
+ accepting the current input byte. */
+
+static re_dfastate_t *
+transit_state_sb (reg_errcode_t *err, re_match_context_t *mctx,
+ re_dfastate_t *state)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ re_node_set next_nodes;
+ re_dfastate_t *next_state;
+ int node_cnt, cur_str_idx = re_string_cur_idx (&mctx->input);
+ unsigned int context;
+
+ *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1);
+ if (BE (*err != REG_NOERROR, 0))
+ return NULL;
+ for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt)
+ {
+ int cur_node = state->nodes.elems[node_cnt];
+ if (check_node_accept (mctx, dfa->nodes + cur_node, cur_str_idx))
+ {
+ *err = re_node_set_merge (&next_nodes,
+ dfa->eclosures + dfa->nexts[cur_node]);
+ if (BE (*err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return NULL;
+ }
+ }
+ }
+ context = re_string_context_at (&mctx->input, cur_str_idx, mctx->eflags);
+ next_state = re_acquire_state_context (err, dfa, &next_nodes, context);
+ /* We don't need to check errors here, since the return value of
+ this function is next_state and ERR is already set. */
+
+ re_node_set_free (&next_nodes);
+ re_string_skip_bytes (&mctx->input, 1);
+ return next_state;
+}
+#endif
+
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t
+internal_function
+transit_state_mb (re_match_context_t *mctx, re_dfastate_t *pstate)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+
+ for (i = 0; i < pstate->nodes.nelem; ++i)
+ {
+ re_node_set dest_nodes, *new_nodes;
+ int cur_node_idx = pstate->nodes.elems[i];
+ int naccepted, dest_idx;
+ unsigned int context;
+ re_dfastate_t *dest_state;
+
+ if (!dfa->nodes[cur_node_idx].accept_mb)
+ continue;
+
+ if (dfa->nodes[cur_node_idx].constraint)
+ {
+ context = re_string_context_at (&mctx->input,
+ re_string_cur_idx (&mctx->input),
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint,
+ context))
+ continue;
+ }
+
+ /* How many bytes the node can accept? */
+ naccepted = check_node_accept_bytes (dfa, cur_node_idx, &mctx->input,
+ re_string_cur_idx (&mctx->input));
+ if (naccepted == 0)
+ continue;
+
+ /* The node can accepts `naccepted' bytes. */
+ dest_idx = re_string_cur_idx (&mctx->input) + naccepted;
+ mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted
+ : mctx->max_mb_elem_len);
+ err = clean_state_log_if_needed (mctx, dest_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+#ifdef DEBUG
+ assert (dfa->nexts[cur_node_idx] != -1);
+#endif
+ new_nodes = dfa->eclosures + dfa->nexts[cur_node_idx];
+
+ dest_state = mctx->state_log[dest_idx];
+ if (dest_state == NULL)
+ dest_nodes = *new_nodes;
+ else
+ {
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes, new_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ context = re_string_context_at (&mctx->input, dest_idx - 1,
+ mctx->eflags);
+ mctx->state_log[dest_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ if (dest_state != NULL)
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0))
+ return err;
+ }
+ return REG_NOERROR;
+}
+#endif /* RE_ENABLE_I18N */
+
+static reg_errcode_t
+internal_function
+transit_state_bkref (re_match_context_t *mctx, const re_node_set *nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int i;
+ int cur_str_idx = re_string_cur_idx (&mctx->input);
+
+ for (i = 0; i < nodes->nelem; ++i)
+ {
+ int dest_str_idx, prev_nelem, bkc_idx;
+ int node_idx = nodes->elems[i];
+ unsigned int context;
+ const re_token_t *node = dfa->nodes + node_idx;
+ re_node_set *new_dest_nodes;
+
+ /* Check whether `node' is a backreference or not. */
+ if (node->type != OP_BACK_REF)
+ continue;
+
+ if (node->constraint)
+ {
+ context = re_string_context_at (&mctx->input, cur_str_idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ continue;
+ }
+
+ /* `node' is a backreference.
+ Check the substring which the substring matched. */
+ bkc_idx = mctx->nbkref_ents;
+ err = get_subexp (mctx, node_idx, cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+
+ /* And add the epsilon closures (which is `new_dest_nodes') of
+ the backreference to appropriate state_log. */
+#ifdef DEBUG
+ assert (dfa->nexts[node_idx] != -1);
+#endif
+ for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx)
+ {
+ int subexp_len;
+ re_dfastate_t *dest_state;
+ struct re_backref_cache_entry *bkref_ent;
+ bkref_ent = mctx->bkref_ents + bkc_idx;
+ if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx)
+ continue;
+ subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from;
+ new_dest_nodes = (subexp_len == 0
+ ? dfa->eclosures + dfa->edests[node_idx].elems[0]
+ : dfa->eclosures + dfa->nexts[node_idx]);
+ dest_str_idx = (cur_str_idx + bkref_ent->subexp_to
+ - bkref_ent->subexp_from);
+ context = re_string_context_at (&mctx->input, dest_str_idx - 1,
+ mctx->eflags);
+ dest_state = mctx->state_log[dest_str_idx];
+ prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0
+ : mctx->state_log[cur_str_idx]->nodes.nelem);
+ /* Add `new_dest_node' to state_log. */
+ if (dest_state == NULL)
+ {
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, new_dest_nodes,
+ context);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ else
+ {
+ re_node_set dest_nodes;
+ err = re_node_set_init_union (&dest_nodes,
+ dest_state->entrance_nodes,
+ new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&dest_nodes);
+ goto free_return;
+ }
+ mctx->state_log[dest_str_idx]
+ = re_acquire_state_context (&err, dfa, &dest_nodes, context);
+ re_node_set_free (&dest_nodes);
+ if (BE (mctx->state_log[dest_str_idx] == NULL
+ && err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ /* We need to check recursively if the backreference can epsilon
+ transit. */
+ if (subexp_len == 0
+ && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem)
+ {
+ err = check_subexp_matching_top (mctx, new_dest_nodes,
+ cur_str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ err = transit_state_bkref (mctx, new_dest_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ goto free_return;
+ }
+ }
+ }
+ err = REG_NOERROR;
+ free_return:
+ return err;
+}
+
+/* Enumerate all the candidates which the backreference BKREF_NODE can match
+ at BKREF_STR_IDX, and register them by match_ctx_add_entry().
+ Note that we might collect inappropriate candidates here.
+ However, the cost of checking them strictly here is too high, then we
+ delay these checking for prune_impossible_nodes(). */
+
+static reg_errcode_t
+internal_function
+get_subexp (re_match_context_t *mctx, int bkref_node, int bkref_str_idx)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int subexp_num, sub_top_idx;
+ const char *buf = (const char *) re_string_get_buffer (&mctx->input);
+ /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */
+ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx);
+ if (cache_idx != -1)
+ {
+ const struct re_backref_cache_entry *entry
+ = mctx->bkref_ents + cache_idx;
+ do
+ if (entry->node == bkref_node)
+ return REG_NOERROR; /* We already checked it. */
+ while (entry++->more);
+ }
+
+ subexp_num = dfa->nodes[bkref_node].opr.idx;
+
+ /* For each sub expression */
+ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx)
+ {
+ reg_errcode_t err;
+ re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx];
+ re_sub_match_last_t *sub_last;
+ int sub_last_idx, sl_str, bkref_str_off;
+
+ if (dfa->nodes[sub_top->node].opr.idx != subexp_num)
+ continue; /* It isn't related. */
+
+ sl_str = sub_top->str_idx;
+ bkref_str_off = bkref_str_idx;
+ /* At first, check the last node of sub expressions we already
+ evaluated. */
+ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx)
+ {
+ int sl_str_diff;
+ sub_last = sub_top->lasts[sub_last_idx];
+ sl_str_diff = sub_last->str_idx - sl_str;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_diff > 0)
+ {
+ if (BE (bkref_str_off + sl_str_diff > mctx->input.valid_len, 0))
+ {
+ /* Not enough chars for a successful match. */
+ if (bkref_str_off + sl_str_diff > mctx->input.len)
+ break;
+
+ err = clean_state_log_if_needed (mctx,
+ bkref_str_off
+ + sl_str_diff);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (memcmp (buf + bkref_str_off, buf + sl_str, sl_str_diff) != 0)
+ /* We don't need to search this sub expression any more. */
+ break;
+ }
+ bkref_str_off += sl_str_diff;
+ sl_str += sl_str_diff;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+
+ /* Reload buf, since the preceding call might have reallocated
+ the buffer. */
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+
+ if (sub_last_idx < sub_top->nlasts)
+ continue;
+ if (sub_last_idx > 0)
+ ++sl_str;
+ /* Then, search for the other last nodes of the sub expression. */
+ for (; sl_str <= bkref_str_idx; ++sl_str)
+ {
+ int cls_node, sl_str_off;
+ const re_node_set *nodes;
+ sl_str_off = sl_str - sub_top->str_idx;
+ /* The matched string by the sub expression match with the substring
+ at the back reference? */
+ if (sl_str_off > 0)
+ {
+ if (BE (bkref_str_off >= mctx->input.valid_len, 0))
+ {
+ /* If we are at the end of the input, we cannot match. */
+ if (bkref_str_off >= mctx->input.len)
+ break;
+
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+
+ buf = (const char *) re_string_get_buffer (&mctx->input);
+ }
+ if (buf [bkref_str_off++] != buf[sl_str - 1])
+ break; /* We don't need to search this sub expression
+ any more. */
+ }
+ if (mctx->state_log[sl_str] == NULL)
+ continue;
+ /* Does this state have a ')' of the sub expression? */
+ nodes = &mctx->state_log[sl_str]->nodes;
+ cls_node = find_subexp_node (dfa, nodes, subexp_num,
+ OP_CLOSE_SUBEXP);
+ if (cls_node == -1)
+ continue; /* No. */
+ if (sub_top->path == NULL)
+ {
+ sub_top->path = calloc (sizeof (state_array_t),
+ sl_str - sub_top->str_idx + 1);
+ if (sub_top->path == NULL)
+ return REG_ESPACE;
+ }
+ /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node
+ in the current context? */
+ err = check_arrival (mctx, sub_top->path, sub_top->node,
+ sub_top->str_idx, cls_node, sl_str,
+ OP_CLOSE_SUBEXP);
+ if (err == REG_NOMATCH)
+ continue;
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str);
+ if (BE (sub_last == NULL, 0))
+ return REG_ESPACE;
+ err = get_subexp_sub (mctx, sub_top, sub_last, bkref_node,
+ bkref_str_idx);
+ if (err == REG_NOMATCH)
+ continue;
+ }
+ }
+ return REG_NOERROR;
+}
+
+/* Helper functions for get_subexp(). */
+
+/* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR.
+ If it can arrive, register the sub expression expressed with SUB_TOP
+ and SUB_LAST. */
+
+static reg_errcode_t
+internal_function
+get_subexp_sub (re_match_context_t *mctx, const re_sub_match_top_t *sub_top,
+ re_sub_match_last_t *sub_last, int bkref_node, int bkref_str)
+{
+ reg_errcode_t err;
+ int to_idx;
+ /* Can the subexpression arrive the back reference? */
+ err = check_arrival (mctx, &sub_last->path, sub_last->node,
+ sub_last->str_idx, bkref_node, bkref_str,
+ OP_OPEN_SUBEXP);
+ if (err != REG_NOERROR)
+ return err;
+ err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx,
+ sub_last->str_idx);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx;
+ return clean_state_log_if_needed (mctx, to_idx);
+}
+
+/* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX.
+ Search '(' if FL_OPEN, or search ')' otherwise.
+ TODO: This function isn't efficient...
+ Because there might be more than one nodes whose types are
+ OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all
+ nodes.
+ E.g. RE: (a){2} */
+
+static int
+internal_function
+find_subexp_node (const re_dfa_t *dfa, const re_node_set *nodes,
+ int subexp_idx, int type)
+{
+ int cls_idx;
+ for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx)
+ {
+ int cls_node = nodes->elems[cls_idx];
+ const re_token_t *node = dfa->nodes + cls_node;
+ if (node->type == type
+ && node->opr.idx == subexp_idx)
+ return cls_node;
+ }
+ return -1;
+}
+
+/* Check whether the node TOP_NODE at TOP_STR can arrive to the node
+ LAST_NODE at LAST_STR. We record the path onto PATH since it will be
+ heavily reused.
+ Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */
+
+static reg_errcode_t
+internal_function
+check_arrival (re_match_context_t *mctx, state_array_t *path, int top_node,
+ int top_str, int last_node, int last_str, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err = REG_NOERROR;
+ int subexp_num, backup_cur_idx, str_idx, null_cnt;
+ re_dfastate_t *cur_state = NULL;
+ re_node_set *cur_nodes, next_nodes;
+ re_dfastate_t **backup_state_log;
+ unsigned int context;
+
+ subexp_num = dfa->nodes[top_node].opr.idx;
+ /* Extend the buffer if we need. */
+ if (BE (path->alloc < last_str + mctx->max_mb_elem_len + 1, 0))
+ {
+ re_dfastate_t **new_array;
+ int old_alloc = path->alloc;
+ path->alloc += last_str + mctx->max_mb_elem_len + 1;
+ new_array = re_realloc (path->array, re_dfastate_t *, path->alloc);
+ if (BE (new_array == NULL, 0))
+ {
+ path->alloc = old_alloc;
+ return REG_ESPACE;
+ }
+ path->array = new_array;
+ memset (new_array + old_alloc, '\0',
+ sizeof (re_dfastate_t *) * (path->alloc - old_alloc));
+ }
+
+ str_idx = path->next_idx ? path->next_idx : top_str;
+
+ /* Temporary modify MCTX. */
+ backup_state_log = mctx->state_log;
+ backup_cur_idx = mctx->input.cur_idx;
+ mctx->state_log = path->array;
+ mctx->input.cur_idx = str_idx;
+
+ /* Setup initial node set. */
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ if (str_idx == top_str)
+ {
+ err = re_node_set_init_1 (&next_nodes, top_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ cur_state = mctx->state_log[str_idx];
+ if (cur_state && cur_state->has_backref)
+ {
+ err = re_node_set_init_copy (&next_nodes, &cur_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ else
+ re_node_set_init_empty (&next_nodes);
+ }
+ if (str_idx == top_str || (cur_state && cur_state->has_backref))
+ {
+ if (next_nodes.nelem)
+ {
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ }
+
+ for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;)
+ {
+ re_node_set_empty (&next_nodes);
+ if (mctx->state_log[str_idx + 1])
+ {
+ err = re_node_set_merge (&next_nodes,
+ &mctx->state_log[str_idx + 1]->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ if (cur_state)
+ {
+ err = check_arrival_add_next_nodes (mctx, str_idx,
+ &cur_state->non_eps_nodes,
+ &next_nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ ++str_idx;
+ if (next_nodes.nelem)
+ {
+ err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ err = expand_bkref_cache (mctx, &next_nodes, str_idx,
+ subexp_num, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ }
+ context = re_string_context_at (&mctx->input, str_idx - 1, mctx->eflags);
+ cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context);
+ if (BE (cur_state == NULL && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&next_nodes);
+ return err;
+ }
+ mctx->state_log[str_idx] = cur_state;
+ null_cnt = cur_state == NULL ? null_cnt + 1 : 0;
+ }
+ re_node_set_free (&next_nodes);
+ cur_nodes = (mctx->state_log[last_str] == NULL ? NULL
+ : &mctx->state_log[last_str]->nodes);
+ path->next_idx = str_idx;
+
+ /* Fix MCTX. */
+ mctx->state_log = backup_state_log;
+ mctx->input.cur_idx = backup_cur_idx;
+
+ /* Then check the current node set has the node LAST_NODE. */
+ if (cur_nodes != NULL && re_node_set_contains (cur_nodes, last_node))
+ return REG_NOERROR;
+
+ return REG_NOMATCH;
+}
+
+/* Helper functions for check_arrival. */
+
+/* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them
+ to NEXT_NODES.
+ TODO: This function is similar to the functions transit_state*(),
+ however this function has many additional works.
+ Can't we unify them? */
+
+static reg_errcode_t
+internal_function
+check_arrival_add_next_nodes (re_match_context_t *mctx, int str_idx,
+ re_node_set *cur_nodes, re_node_set *next_nodes)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ int result;
+ int cur_idx;
+ reg_errcode_t err = REG_NOERROR;
+ re_node_set union_set;
+ re_node_set_init_empty (&union_set);
+ for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx)
+ {
+ int naccepted = 0;
+ int cur_node = cur_nodes->elems[cur_idx];
+#ifdef DEBUG
+ re_token_type_t type = dfa->nodes[cur_node].type;
+ assert (!IS_EPSILON_NODE (type));
+#endif
+#ifdef RE_ENABLE_I18N
+ /* If the node may accept `multi byte'. */
+ if (dfa->nodes[cur_node].accept_mb)
+ {
+ naccepted = check_node_accept_bytes (dfa, cur_node, &mctx->input,
+ str_idx);
+ if (naccepted > 1)
+ {
+ re_dfastate_t *dest_state;
+ int next_node = dfa->nexts[cur_node];
+ int next_idx = str_idx + naccepted;
+ dest_state = mctx->state_log[next_idx];
+ re_node_set_empty (&union_set);
+ if (dest_state)
+ {
+ err = re_node_set_merge (&union_set, &dest_state->nodes);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ result = re_node_set_insert (&union_set, next_node);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ mctx->state_log[next_idx] = re_acquire_state (&err, dfa,
+ &union_set);
+ if (BE (mctx->state_log[next_idx] == NULL
+ && err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&union_set);
+ return err;
+ }
+ }
+ }
+#endif /* RE_ENABLE_I18N */
+ if (naccepted
+ || check_node_accept (mctx, dfa->nodes + cur_node, str_idx))
+ {
+ result = re_node_set_insert (next_nodes, dfa->nexts[cur_node]);
+ if (BE (result < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ return REG_ESPACE;
+ }
+ }
+ }
+ re_node_set_free (&union_set);
+ return REG_NOERROR;
+}
+
+/* For all the nodes in CUR_NODES, add the epsilon closures of them to
+ CUR_NODES, however exclude the nodes which are:
+ - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN.
+ - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN.
+*/
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl (const re_dfa_t *dfa, re_node_set *cur_nodes,
+ int ex_subexp, int type)
+{
+ reg_errcode_t err;
+ int idx, outside_node;
+ re_node_set new_nodes;
+#ifdef DEBUG
+ assert (cur_nodes->nelem);
+#endif
+ err = re_node_set_alloc (&new_nodes, cur_nodes->nelem);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ /* Create a new node set NEW_NODES with the nodes which are epsilon
+ closures of the node in CUR_NODES. */
+
+ for (idx = 0; idx < cur_nodes->nelem; ++idx)
+ {
+ int cur_node = cur_nodes->elems[idx];
+ const re_node_set *eclosure = dfa->eclosures + cur_node;
+ outside_node = find_subexp_node (dfa, eclosure, ex_subexp, type);
+ if (outside_node == -1)
+ {
+ /* There are no problematic nodes, just merge them. */
+ err = re_node_set_merge (&new_nodes, eclosure);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ else
+ {
+ /* There are problematic nodes, re-calculate incrementally. */
+ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node,
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ {
+ re_node_set_free (&new_nodes);
+ return err;
+ }
+ }
+ }
+ re_node_set_free (cur_nodes);
+ *cur_nodes = new_nodes;
+ return REG_NOERROR;
+}
+
+/* Helper function for check_arrival_expand_ecl.
+ Check incrementally the epsilon closure of TARGET, and if it isn't
+ problematic append it to DST_NODES. */
+
+static reg_errcode_t
+internal_function
+check_arrival_expand_ecl_sub (const re_dfa_t *dfa, re_node_set *dst_nodes,
+ int target, int ex_subexp, int type)
+{
+ int cur_node;
+ for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);)
+ {
+ int err;
+
+ if (dfa->nodes[cur_node].type == type
+ && dfa->nodes[cur_node].opr.idx == ex_subexp)
+ {
+ if (type == OP_CLOSE_SUBEXP)
+ {
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ }
+ break;
+ }
+ err = re_node_set_insert (dst_nodes, cur_node);
+ if (BE (err == -1, 0))
+ return REG_ESPACE;
+ if (dfa->edests[cur_node].nelem == 0)
+ break;
+ if (dfa->edests[cur_node].nelem == 2)
+ {
+ err = check_arrival_expand_ecl_sub (dfa, dst_nodes,
+ dfa->edests[cur_node].elems[1],
+ ex_subexp, type);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ cur_node = dfa->edests[cur_node].elems[0];
+ }
+ return REG_NOERROR;
+}
+
+
+/* For all the back references in the current state, calculate the
+ destination of the back references by the appropriate entry
+ in MCTX->BKREF_ENTS. */
+
+static reg_errcode_t
+internal_function
+expand_bkref_cache (re_match_context_t *mctx, re_node_set *cur_nodes,
+ int cur_str, int subexp_num, int type)
+{
+ const re_dfa_t *const dfa = mctx->dfa;
+ reg_errcode_t err;
+ int cache_idx_start = search_cur_bkref_entry (mctx, cur_str);
+ struct re_backref_cache_entry *ent;
+
+ if (cache_idx_start == -1)
+ return REG_NOERROR;
+
+ restart:
+ ent = mctx->bkref_ents + cache_idx_start;
+ do
+ {
+ int to_idx, next_node;
+
+ /* Is this entry ENT is appropriate? */
+ if (!re_node_set_contains (cur_nodes, ent->node))
+ continue; /* No. */
+
+ to_idx = cur_str + ent->subexp_to - ent->subexp_from;
+ /* Calculate the destination of the back reference, and append it
+ to MCTX->STATE_LOG. */
+ if (to_idx == cur_str)
+ {
+ /* The backreference did epsilon transit, we must re-check all the
+ node in the current state. */
+ re_node_set new_dests;
+ reg_errcode_t err2, err3;
+ next_node = dfa->edests[ent->node].elems[0];
+ if (re_node_set_contains (cur_nodes, next_node))
+ continue;
+ err = re_node_set_init_1 (&new_dests, next_node);
+ err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, type);
+ err3 = re_node_set_merge (cur_nodes, &new_dests);
+ re_node_set_free (&new_dests);
+ if (BE (err != REG_NOERROR || err2 != REG_NOERROR
+ || err3 != REG_NOERROR, 0))
+ {
+ err = (err != REG_NOERROR ? err
+ : (err2 != REG_NOERROR ? err2 : err3));
+ return err;
+ }
+ /* TODO: It is still inefficient... */
+ goto restart;
+ }
+ else
+ {
+ re_node_set union_set;
+ next_node = dfa->nexts[ent->node];
+ if (mctx->state_log[to_idx])
+ {
+ int ret;
+ if (re_node_set_contains (&mctx->state_log[to_idx]->nodes,
+ next_node))
+ continue;
+ err = re_node_set_init_copy (&union_set,
+ &mctx->state_log[to_idx]->nodes);
+ ret = re_node_set_insert (&union_set, next_node);
+ if (BE (err != REG_NOERROR || ret < 0, 0))
+ {
+ re_node_set_free (&union_set);
+ err = err != REG_NOERROR ? err : REG_ESPACE;
+ return err;
+ }
+ }
+ else
+ {
+ err = re_node_set_init_1 (&union_set, next_node);
+ if (BE (err != REG_NOERROR, 0))
+ return err;
+ }
+ mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set);
+ re_node_set_free (&union_set);
+ if (BE (mctx->state_log[to_idx] == NULL
+ && err != REG_NOERROR, 0))
+ return err;
+ }
+ }
+ while (ent++->more);
+ return REG_NOERROR;
+}
+
+/* Build transition table for the state.
+ Return 1 if succeeded, otherwise return NULL. */
+
+static int
+internal_function
+build_trtable (const re_dfa_t *dfa, re_dfastate_t *state)
+{
+ reg_errcode_t err;
+ int i, j, ch, need_word_trtable = 0;
+ bitset_word_t elem, mask;
+ bool dests_node_malloced = false;
+ bool dest_states_malloced = false;
+ int ndests; /* Number of the destination states from `state'. */
+ re_dfastate_t **trtable;
+ re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl;
+ re_node_set follows, *dests_node;
+ bitset_t *dests_ch;
+ bitset_t acceptable;
+
+ struct dests_alloc
+ {
+ re_node_set dests_node[SBC_MAX];
+ bitset_t dests_ch[SBC_MAX];
+ } *dests_alloc;
+
+ /* We build DFA states which corresponds to the destination nodes
+ from `state'. `dests_node[i]' represents the nodes which i-th
+ destination state contains, and `dests_ch[i]' represents the
+ characters which i-th destination state accepts. */
+ if (__libc_use_alloca (sizeof (struct dests_alloc)))
+ dests_alloc = (struct dests_alloc *) alloca (sizeof (struct dests_alloc));
+ else
+ {
+ dests_alloc = re_malloc (struct dests_alloc, 1);
+ if (BE (dests_alloc == NULL, 0))
+ return 0;
+ dests_node_malloced = true;
+ }
+ dests_node = dests_alloc->dests_node;
+ dests_ch = dests_alloc->dests_ch;
+
+ /* Initialize transiton table. */
+ state->word_trtable = state->trtable = NULL;
+
+ /* At first, group all nodes belonging to `state' into several
+ destinations. */
+ ndests = group_nodes_into_DFAstates (dfa, state, dests_node, dests_ch);
+ if (BE (ndests <= 0, 0))
+ {
+ if (dests_node_malloced)
+ free (dests_alloc);
+ /* Return 0 in case of an error, 1 otherwise. */
+ if (ndests == 0)
+ {
+ state->trtable = (re_dfastate_t **)
+ calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ return 1;
+ }
+ return 0;
+ }
+
+ err = re_node_set_alloc (&follows, ndests + 1);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset_t)) * SBC_MAX
+ + ndests * 3 * sizeof (re_dfastate_t *)))
+ dest_states = (re_dfastate_t **)
+ alloca (ndests * 3 * sizeof (re_dfastate_t *));
+ else
+ {
+ dest_states = (re_dfastate_t **)
+ malloc (ndests * 3 * sizeof (re_dfastate_t *));
+ if (BE (dest_states == NULL, 0))
+ {
+out_free:
+ if (dest_states_malloced)
+ free (dest_states);
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+ if (dests_node_malloced)
+ free (dests_alloc);
+ return 0;
+ }
+ dest_states_malloced = true;
+ }
+ dest_states_word = dest_states + ndests;
+ dest_states_nl = dest_states_word + ndests;
+ bitset_empty (acceptable);
+
+ /* Then build the states for all destinations. */
+ for (i = 0; i < ndests; ++i)
+ {
+ int next_node;
+ re_node_set_empty (&follows);
+ /* Merge the follows of this destination states. */
+ for (j = 0; j < dests_node[i].nelem; ++j)
+ {
+ next_node = dfa->nexts[dests_node[i].elems[j]];
+ if (next_node != -1)
+ {
+ err = re_node_set_merge (&follows, dfa->eclosures + next_node);
+ if (BE (err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ }
+ dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0);
+ if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ /* If the new state has context constraint,
+ build appropriate states for these contexts. */
+ if (dest_states[i]->has_constraint)
+ {
+ dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_WORD);
+ if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+
+ if (dest_states[i] != dest_states_word[i] && dfa->mb_cur_max > 1)
+ need_word_trtable = 1;
+
+ dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows,
+ CONTEXT_NEWLINE);
+ if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0))
+ goto out_free;
+ }
+ else
+ {
+ dest_states_word[i] = dest_states[i];
+ dest_states_nl[i] = dest_states[i];
+ }
+ bitset_merge (acceptable, dests_ch[i]);
+ }
+
+ if (!BE (need_word_trtable, 0))
+ {
+ /* We don't care about whether the following character is a word
+ character, or we are in a single-byte character set so we can
+ discern by looking at the character code: allocate a
+ 256-entry transition table. */
+ trtable = state->trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ if (dfa->word_char[i] & mask)
+ trtable[ch] = dest_states_word[j];
+ else
+ trtable[ch] = dest_states[j];
+ }
+ }
+ else
+ {
+ /* We care about whether the following character is a word
+ character, and we are in a multi-byte character set: discern
+ by looking at the character code: build two 256-entry
+ transition tables, one starting at trtable[0] and one
+ starting at trtable[SBC_MAX]. */
+ trtable = state->word_trtable =
+ (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), 2 * SBC_MAX);
+ if (BE (trtable == NULL, 0))
+ goto out_free;
+
+ /* For all characters ch...: */
+ for (i = 0; i < BITSET_WORDS; ++i)
+ for (ch = i * BITSET_WORD_BITS, elem = acceptable[i], mask = 1;
+ elem;
+ mask <<= 1, elem >>= 1, ++ch)
+ if (BE (elem & 1, 0))
+ {
+ /* There must be exactly one destination which accepts
+ character ch. See group_nodes_into_DFAstates. */
+ for (j = 0; (dests_ch[j][i] & mask) == 0; ++j)
+ ;
+
+ /* j-th destination accepts the word character ch. */
+ trtable[ch] = dest_states[j];
+ trtable[ch + SBC_MAX] = dest_states_word[j];
+ }
+ }
+
+ /* new line */
+ if (bitset_contain (acceptable, NEWLINE_CHAR))
+ {
+ /* The current state accepts newline character. */
+ for (j = 0; j < ndests; ++j)
+ if (bitset_contain (dests_ch[j], NEWLINE_CHAR))
+ {
+ /* k-th destination accepts newline character. */
+ trtable[NEWLINE_CHAR] = dest_states_nl[j];
+ if (need_word_trtable)
+ trtable[NEWLINE_CHAR + SBC_MAX] = dest_states_nl[j];
+ /* There must be only one destination which accepts
+ newline. See group_nodes_into_DFAstates. */
+ break;
+ }
+ }
+
+ if (dest_states_malloced)
+ free (dest_states);
+
+ re_node_set_free (&follows);
+ for (i = 0; i < ndests; ++i)
+ re_node_set_free (dests_node + i);
+
+ if (dests_node_malloced)
+ free (dests_alloc);
+
+ return 1;
+}
+
+/* Group all nodes belonging to STATE into several destinations.
+ Then for all destinations, set the nodes belonging to the destination
+ to DESTS_NODE[i] and set the characters accepted by the destination
+ to DEST_CH[i]. This function return the number of destinations. */
+
+static int
+internal_function
+group_nodes_into_DFAstates (const re_dfa_t *dfa, const re_dfastate_t *state,
+ re_node_set *dests_node, bitset_t *dests_ch)
+{
+ reg_errcode_t err;
+ int result;
+ int i, j, k;
+ int ndests; /* Number of the destinations from `state'. */
+ bitset_t accepts; /* Characters a node can accept. */
+ const re_node_set *cur_nodes = &state->nodes;
+ bitset_empty (accepts);
+ ndests = 0;
+
+ /* For all the nodes belonging to `state', */
+ for (i = 0; i < cur_nodes->nelem; ++i)
+ {
+ re_token_t *node = &dfa->nodes[cur_nodes->elems[i]];
+ re_token_type_t type = node->type;
+ unsigned int constraint = node->constraint;
+
+ /* Enumerate all single byte character this node can accept. */
+ if (type == CHARACTER)
+ bitset_set (accepts, node->opr.c);
+ else if (type == SIMPLE_BRACKET)
+ {
+ bitset_merge (accepts, node->opr.sbcset);
+ }
+ else if (type == OP_PERIOD)
+ {
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ bitset_merge (accepts, dfa->sb_char);
+ else
+#endif
+ bitset_set_all (accepts);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#ifdef RE_ENABLE_I18N
+ else if (type == OP_UTF8_PERIOD)
+ {
+ memset (accepts, '\xff', sizeof (bitset_t) / 2);
+ if (!(dfa->syntax & RE_DOT_NEWLINE))
+ bitset_clear (accepts, '\n');
+ if (dfa->syntax & RE_DOT_NOT_NULL)
+ bitset_clear (accepts, '\0');
+ }
+#endif
+ else
+ continue;
+
+ /* Check the `accepts' and sift the characters which are not
+ match it the context. */
+ if (constraint)
+ {
+ if (constraint & NEXT_NEWLINE_CONSTRAINT)
+ {
+ bool accepts_newline = bitset_contain (accepts, NEWLINE_CHAR);
+ bitset_empty (accepts);
+ if (accepts_newline)
+ bitset_set (accepts, NEWLINE_CHAR);
+ else
+ continue;
+ }
+ if (constraint & NEXT_ENDBUF_CONSTRAINT)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+
+ if (constraint & NEXT_WORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && !node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= (dfa->word_char[j] | ~dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ if (constraint & NEXT_NOTWORD_CONSTRAINT)
+ {
+ bitset_word_t any_set = 0;
+ if (type == CHARACTER && node->word_char)
+ {
+ bitset_empty (accepts);
+ continue;
+ }
+#ifdef RE_ENABLE_I18N
+ if (dfa->mb_cur_max > 1)
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~(dfa->word_char[j] & dfa->sb_char[j]));
+ else
+#endif
+ for (j = 0; j < BITSET_WORDS; ++j)
+ any_set |= (accepts[j] &= ~dfa->word_char[j]);
+ if (!any_set)
+ continue;
+ }
+ }
+
+ /* Then divide `accepts' into DFA states, or create a new
+ state. Above, we make sure that accepts is not empty. */
+ for (j = 0; j < ndests; ++j)
+ {
+ bitset_t intersec; /* Intersection sets, see below. */
+ bitset_t remains;
+ /* Flags, see below. */
+ bitset_word_t has_intersec, not_subset, not_consumed;
+
+ /* Optimization, skip if this state doesn't accept the character. */
+ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c))
+ continue;
+
+ /* Enumerate the intersection set of this state and `accepts'. */
+ has_intersec = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k];
+ /* And skip if the intersection set is empty. */
+ if (!has_intersec)
+ continue;
+
+ /* Then check if this state is a subset of `accepts'. */
+ not_subset = not_consumed = 0;
+ for (k = 0; k < BITSET_WORDS; ++k)
+ {
+ not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k];
+ not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k];
+ }
+
+ /* If this state isn't a subset of `accepts', create a
+ new group state, which has the `remains'. */
+ if (not_subset)
+ {
+ bitset_copy (dests_ch[ndests], remains);
+ bitset_copy (dests_ch[j], intersec);
+ err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ }
+
+ /* Put the position in the current group. */
+ result = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]);
+ if (BE (result < 0, 0))
+ goto error_return;
+
+ /* If all characters are consumed, go to next node. */
+ if (!not_consumed)
+ break;
+ }
+ /* Some characters remain, create a new group. */
+ if (j == ndests)
+ {
+ bitset_copy (dests_ch[ndests], accepts);
+ err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]);
+ if (BE (err != REG_NOERROR, 0))
+ goto error_return;
+ ++ndests;
+ bitset_empty (accepts);
+ }
+ }
+ return ndests;
+ error_return:
+ for (j = 0; j < ndests; ++j)
+ re_node_set_free (dests_node + j);
+ return -1;
+}
+
+#ifdef RE_ENABLE_I18N
+/* Check how many bytes the node `dfa->nodes[node_idx]' accepts.
+ Return the number of the bytes the node accepts.
+ STR_IDX is the current index of the input string.
+
+ This function handles the nodes which can accept one character, or
+ one collating element like '.', '[a-z]', opposite to the other nodes
+ can only accept one byte. */
+
+static int
+internal_function
+check_node_accept_bytes (const re_dfa_t *dfa, int node_idx,
+ const re_string_t *input, int str_idx)
+{
+ const re_token_t *node = dfa->nodes + node_idx;
+ int char_len, elem_len;
+ int i;
+
+ if (BE (node->type == OP_UTF8_PERIOD, 0))
+ {
+ unsigned char c = re_string_byte_at (input, str_idx), d;
+ if (BE (c < 0xc2, 1))
+ return 0;
+
+ if (str_idx + 2 > input->len)
+ return 0;
+
+ d = re_string_byte_at (input, str_idx + 1);
+ if (c < 0xe0)
+ return (d < 0x80 || d > 0xbf) ? 0 : 2;
+ else if (c < 0xf0)
+ {
+ char_len = 3;
+ if (c == 0xe0 && d < 0xa0)
+ return 0;
+ }
+ else if (c < 0xf8)
+ {
+ char_len = 4;
+ if (c == 0xf0 && d < 0x90)
+ return 0;
+ }
+ else if (c < 0xfc)
+ {
+ char_len = 5;
+ if (c == 0xf8 && d < 0x88)
+ return 0;
+ }
+ else if (c < 0xfe)
+ {
+ char_len = 6;
+ if (c == 0xfc && d < 0x84)
+ return 0;
+ }
+ else
+ return 0;
+
+ if (str_idx + char_len > input->len)
+ return 0;
+
+ for (i = 1; i < char_len; ++i)
+ {
+ d = re_string_byte_at (input, str_idx + i);
+ if (d < 0x80 || d > 0xbf)
+ return 0;
+ }
+ return char_len;
+ }
+
+ char_len = re_string_char_size_at (input, str_idx);
+ if (node->type == OP_PERIOD)
+ {
+ if (char_len <= 1)
+ return 0;
+ /* FIXME: I don't think this if is needed, as both '\n'
+ and '\0' are char_len == 1. */
+ /* '.' accepts any one character except the following two cases. */
+ if ((!(dfa->syntax & RE_DOT_NEWLINE) &&
+ re_string_byte_at (input, str_idx) == '\n') ||
+ ((dfa->syntax & RE_DOT_NOT_NULL) &&
+ re_string_byte_at (input, str_idx) == '\0'))
+ return 0;
+ return char_len;
+ }
+
+ elem_len = re_string_elem_size_at (input, str_idx);
+ if ((elem_len <= 1 && char_len <= 1) || char_len == 0)
+ return 0;
+
+ if (node->type == COMPLEX_BRACKET)
+ {
+ const re_charset_t *cset = node->opr.mbcset;
+# ifdef _LIBC
+ const unsigned char *pin
+ = ((const unsigned char *) re_string_get_buffer (input) + str_idx);
+ int j;
+ uint32_t nrules;
+# endif /* _LIBC */
+ int match_len = 0;
+ wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars)
+ ? re_string_wchar_at (input, str_idx) : 0);
+
+ /* match with multibyte character? */
+ for (i = 0; i < cset->nmbchars; ++i)
+ if (wc == cset->mbchars[i])
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ /* match with character_class? */
+ for (i = 0; i < cset->nchar_classes; ++i)
+ {
+ wctype_t wt = cset->char_classes[i];
+ if (__iswctype (wc, wt))
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+# ifdef _LIBC
+ nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules != 0)
+ {
+ unsigned int in_collseq = 0;
+ const int32_t *table, *indirect;
+ const unsigned char *weights, *extra;
+ const char *collseqwc;
+ int32_t idx;
+ /* This #include defines a local function! */
+# include <locale/weight.h>
+
+ /* match with collating_symbol? */
+ if (cset->ncoll_syms)
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ for (i = 0; i < cset->ncoll_syms; ++i)
+ {
+ const unsigned char *coll_sym = extra + cset->coll_syms[i];
+ /* Compare the length of input collating element and
+ the length of current collating element. */
+ if (*coll_sym != elem_len)
+ continue;
+ /* Compare each bytes. */
+ for (j = 0; j < *coll_sym; j++)
+ if (pin[j] != coll_sym[1 + j])
+ break;
+ if (j == *coll_sym)
+ {
+ /* Match if every bytes is equal. */
+ match_len = j;
+ goto check_node_accept_bytes_match;
+ }
+ }
+
+ if (cset->nranges)
+ {
+ if (elem_len <= char_len)
+ {
+ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC);
+ in_collseq = __collseq_table_lookup (collseqwc, wc);
+ }
+ else
+ in_collseq = find_collation_sequence_value (pin, elem_len);
+ }
+ /* match with range expression? */
+ for (i = 0; i < cset->nranges; ++i)
+ if (cset->range_starts[i] <= in_collseq
+ && in_collseq <= cset->range_ends[i])
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+
+ /* match with equivalence_class? */
+ if (cset->nequiv_classes)
+ {
+ const unsigned char *cp = pin;
+ table = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB);
+ weights = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB);
+ extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB);
+ indirect = (const int32_t *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB);
+ idx = findidx (&cp);
+ if (idx > 0)
+ for (i = 0; i < cset->nequiv_classes; ++i)
+ {
+ int32_t equiv_class_idx = cset->equiv_classes[i];
+ size_t weight_len = weights[idx];
+ if (weight_len == weights[equiv_class_idx])
+ {
+ int cnt = 0;
+ while (cnt <= weight_len
+ && (weights[equiv_class_idx + 1 + cnt]
+ == weights[idx + 1 + cnt]))
+ ++cnt;
+ if (cnt > weight_len)
+ {
+ match_len = elem_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ }
+ }
+ else
+# endif /* _LIBC */
+ {
+ /* match with range expression? */
+#if __GNUC__ >= 2
+ wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'};
+#else
+ wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'};
+ cmp_buf[2] = wc;
+#endif
+ for (i = 0; i < cset->nranges; ++i)
+ {
+ cmp_buf[0] = cset->range_starts[i];
+ cmp_buf[4] = cset->range_ends[i];
+ if (wcscoll (cmp_buf, cmp_buf + 2) <= 0
+ && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0)
+ {
+ match_len = char_len;
+ goto check_node_accept_bytes_match;
+ }
+ }
+ }
+ check_node_accept_bytes_match:
+ if (!cset->non_match)
+ return match_len;
+ else
+ {
+ if (match_len > 0)
+ return 0;
+ else
+ return (elem_len > char_len) ? elem_len : char_len;
+ }
+ }
+ return 0;
+}
+
+# ifdef _LIBC
+static unsigned int
+internal_function
+find_collation_sequence_value (const unsigned char *mbs, size_t mbs_len)
+{
+ uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES);
+ if (nrules == 0)
+ {
+ if (mbs_len == 1)
+ {
+ /* No valid character. Match it as a single byte character. */
+ const unsigned char *collseq = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB);
+ return collseq[mbs[0]];
+ }
+ return UINT_MAX;
+ }
+ else
+ {
+ int32_t idx;
+ const unsigned char *extra = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB);
+ int32_t extrasize = (const unsigned char *)
+ _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB + 1) - extra;
+
+ for (idx = 0; idx < extrasize;)
+ {
+ int mbs_cnt, found = 0;
+ int32_t elem_mbs_len;
+ /* Skip the name of collating element name. */
+ idx = idx + extra[idx] + 1;
+ elem_mbs_len = extra[idx++];
+ if (mbs_len == elem_mbs_len)
+ {
+ for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt)
+ if (extra[idx + mbs_cnt] != mbs[mbs_cnt])
+ break;
+ if (mbs_cnt == elem_mbs_len)
+ /* Found the entry. */
+ found = 1;
+ }
+ /* Skip the byte sequence of the collating element. */
+ idx += elem_mbs_len;
+ /* Adjust for the alignment. */
+ idx = (idx + 3) & ~3;
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ /* Skip the wide char sequence of the collating element. */
+ idx = idx + sizeof (uint32_t) * (extra[idx] + 1);
+ /* If we found the entry, return the sequence value. */
+ if (found)
+ return *(uint32_t *) (extra + idx);
+ /* Skip the collation sequence value. */
+ idx += sizeof (uint32_t);
+ }
+ return UINT_MAX;
+ }
+}
+# endif /* _LIBC */
+#endif /* RE_ENABLE_I18N */
+
+/* Check whether the node accepts the byte which is IDX-th
+ byte of the INPUT. */
+
+static int
+internal_function
+check_node_accept (const re_match_context_t *mctx, const re_token_t *node,
+ int idx)
+{
+ unsigned char ch;
+ ch = re_string_byte_at (&mctx->input, idx);
+ switch (node->type)
+ {
+ case CHARACTER:
+ if (node->opr.c != ch)
+ return 0;
+ break;
+
+ case SIMPLE_BRACKET:
+ if (!bitset_contain (node->opr.sbcset, ch))
+ return 0;
+ break;
+
+#ifdef RE_ENABLE_I18N
+ case OP_UTF8_PERIOD:
+ if (ch >= 0x80)
+ return 0;
+ /* FALLTHROUGH */
+#endif
+ case OP_PERIOD:
+ if ((ch == '\n' && !(mctx->dfa->syntax & RE_DOT_NEWLINE))
+ || (ch == '\0' && (mctx->dfa->syntax & RE_DOT_NOT_NULL)))
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (node->constraint)
+ {
+ /* The node has constraints. Check whether the current context
+ satisfies the constraints. */
+ unsigned int context = re_string_context_at (&mctx->input, idx,
+ mctx->eflags);
+ if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Extend the buffers, if the buffers have run out. */
+
+static reg_errcode_t
+internal_function
+extend_buffers (re_match_context_t *mctx)
+{
+ reg_errcode_t ret;
+ re_string_t *pstr = &mctx->input;
+
+ /* Double the lengthes of the buffers. */
+ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+
+ if (mctx->state_log != NULL)
+ {
+ /* And double the length of state_log. */
+ /* XXX We have no indication of the size of this buffer. If this
+ allocation fail we have no indication that the state_log array
+ does not have the right size. */
+ re_dfastate_t **new_array = re_realloc (mctx->state_log, re_dfastate_t *,
+ pstr->bufs_len + 1);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->state_log = new_array;
+ }
+
+ /* Then reconstruct the buffers. */
+ if (pstr->icase)
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+ ret = build_wcs_upper_buffer (pstr);
+ if (BE (ret != REG_NOERROR, 0))
+ return ret;
+ }
+ else
+#endif /* RE_ENABLE_I18N */
+ build_upper_buffer (pstr);
+ }
+ else
+ {
+#ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ build_wcs_buffer (pstr);
+ else
+#endif /* RE_ENABLE_I18N */
+ {
+ if (pstr->trans != NULL)
+ re_string_translate_buffer (pstr);
+ }
+ }
+ return REG_NOERROR;
+}
+
+
+/* Functions for matching context. */
+
+/* Initialize MCTX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_init (re_match_context_t *mctx, int eflags, int n)
+{
+ mctx->eflags = eflags;
+ mctx->match_last = -1;
+ if (n > 0)
+ {
+ mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n);
+ mctx->sub_tops = re_malloc (re_sub_match_top_t *, n);
+ if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0))
+ return REG_ESPACE;
+ }
+ /* Already zero-ed by the caller.
+ else
+ mctx->bkref_ents = NULL;
+ mctx->nbkref_ents = 0;
+ mctx->nsub_tops = 0; */
+ mctx->abkref_ents = n;
+ mctx->max_mb_elem_len = 1;
+ mctx->asub_tops = n;
+ return REG_NOERROR;
+}
+
+/* Clean the entries which depend on the current input in MCTX.
+ This function must be invoked when the matcher changes the start index
+ of the input, or changes the input string. */
+
+static void
+internal_function
+match_ctx_clean (re_match_context_t *mctx)
+{
+ int st_idx;
+ for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx)
+ {
+ int sl_idx;
+ re_sub_match_top_t *top = mctx->sub_tops[st_idx];
+ for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx)
+ {
+ re_sub_match_last_t *last = top->lasts[sl_idx];
+ re_free (last->path.array);
+ re_free (last);
+ }
+ re_free (top->lasts);
+ if (top->path)
+ {
+ re_free (top->path->array);
+ re_free (top->path);
+ }
+ free (top);
+ }
+
+ mctx->nsub_tops = 0;
+ mctx->nbkref_ents = 0;
+}
+
+/* Free all the memory associated with MCTX. */
+
+static void
+internal_function
+match_ctx_free (re_match_context_t *mctx)
+{
+ /* First, free all the memory associated with MCTX->SUB_TOPS. */
+ match_ctx_clean (mctx);
+ re_free (mctx->sub_tops);
+ re_free (mctx->bkref_ents);
+}
+
+/* Add a new backreference entry to MCTX.
+ Note that we assume that caller never call this function with duplicate
+ entry, and call with STR_IDX which isn't smaller than any existing entry.
+*/
+
+static reg_errcode_t
+internal_function
+match_ctx_add_entry (re_match_context_t *mctx, int node, int str_idx, int from,
+ int to)
+{
+ if (mctx->nbkref_ents >= mctx->abkref_ents)
+ {
+ struct re_backref_cache_entry* new_entry;
+ new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry,
+ mctx->abkref_ents * 2);
+ if (BE (new_entry == NULL, 0))
+ {
+ re_free (mctx->bkref_ents);
+ return REG_ESPACE;
+ }
+ mctx->bkref_ents = new_entry;
+ memset (mctx->bkref_ents + mctx->nbkref_ents, '\0',
+ sizeof (struct re_backref_cache_entry) * mctx->abkref_ents);
+ mctx->abkref_ents *= 2;
+ }
+ if (mctx->nbkref_ents > 0
+ && mctx->bkref_ents[mctx->nbkref_ents - 1].str_idx == str_idx)
+ mctx->bkref_ents[mctx->nbkref_ents - 1].more = 1;
+
+ mctx->bkref_ents[mctx->nbkref_ents].node = node;
+ mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from;
+ mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to;
+
+ /* This is a cache that saves negative results of check_dst_limits_calc_pos.
+ If bit N is clear, means that this entry won't epsilon-transition to
+ an OP_OPEN_SUBEXP or OP_CLOSE_SUBEXP for the N+1-th subexpression. If
+ it is set, check_dst_limits_calc_pos_1 will recurse and try to find one
+ such node.
+
+ A backreference does not epsilon-transition unless it is empty, so set
+ to all zeros if FROM != TO. */
+ mctx->bkref_ents[mctx->nbkref_ents].eps_reachable_subexps_map
+ = (from == to ? ~0 : 0);
+
+ mctx->bkref_ents[mctx->nbkref_ents++].more = 0;
+ if (mctx->max_mb_elem_len < to - from)
+ mctx->max_mb_elem_len = to - from;
+ return REG_NOERROR;
+}
+
+/* Search for the first entry which has the same str_idx, or -1 if none is
+ found. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */
+
+static int
+internal_function
+search_cur_bkref_entry (const re_match_context_t *mctx, int str_idx)
+{
+ int left, right, mid, last;
+ last = right = mctx->nbkref_ents;
+ for (left = 0; left < right;)
+ {
+ mid = (left + right) / 2;
+ if (mctx->bkref_ents[mid].str_idx < str_idx)
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ if (left < last && mctx->bkref_ents[left].str_idx == str_idx)
+ return left;
+ else
+ return -1;
+}
+
+/* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches
+ at STR_IDX. */
+
+static reg_errcode_t
+internal_function
+match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx)
+{
+#ifdef DEBUG
+ assert (mctx->sub_tops != NULL);
+ assert (mctx->asub_tops > 0);
+#endif
+ if (BE (mctx->nsub_tops == mctx->asub_tops, 0))
+ {
+ int new_asub_tops = mctx->asub_tops * 2;
+ re_sub_match_top_t **new_array = re_realloc (mctx->sub_tops,
+ re_sub_match_top_t *,
+ new_asub_tops);
+ if (BE (new_array == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops = new_array;
+ mctx->asub_tops = new_asub_tops;
+ }
+ mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t));
+ if (BE (mctx->sub_tops[mctx->nsub_tops] == NULL, 0))
+ return REG_ESPACE;
+ mctx->sub_tops[mctx->nsub_tops]->node = node;
+ mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx;
+ return REG_NOERROR;
+}
+
+/* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches
+ at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */
+
+static re_sub_match_last_t *
+internal_function
+match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx)
+{
+ re_sub_match_last_t *new_entry;
+ if (BE (subtop->nlasts == subtop->alasts, 0))
+ {
+ int new_alasts = 2 * subtop->alasts + 1;
+ re_sub_match_last_t **new_array = re_realloc (subtop->lasts,
+ re_sub_match_last_t *,
+ new_alasts);
+ if (BE (new_array == NULL, 0))
+ return NULL;
+ subtop->lasts = new_array;
+ subtop->alasts = new_alasts;
+ }
+ new_entry = calloc (1, sizeof (re_sub_match_last_t));
+ if (BE (new_entry != NULL, 1))
+ {
+ subtop->lasts[subtop->nlasts] = new_entry;
+ new_entry->node = node;
+ new_entry->str_idx = str_idx;
+ ++subtop->nlasts;
+ }
+ return new_entry;
+}
+
+static void
+internal_function
+sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts,
+ re_dfastate_t **limited_sts, int last_node, int last_str_idx)
+{
+ sctx->sifted_states = sifted_sts;
+ sctx->limited_states = limited_sts;
+ sctx->last_node = last_node;
+ sctx->last_str_idx = last_str_idx;
+ re_node_set_init_empty (&sctx->limits);
+}
diff --git a/node_modules/mmmagic/deps/libmagic/msvc/stdint.h b/node_modules/mmmagic/deps/libmagic/msvc/stdint.h
new file mode 100644
index 0000000..d02608a
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/msvc/stdint.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/node_modules/mmmagic/deps/libmagic/src/BNF b/node_modules/mmmagic/deps/libmagic/src/BNF
new file mode 100644
index 0000000..243532f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/BNF
@@ -0,0 +1,151 @@
+This is a first attempt to document the grammar used by magic(5), with
+hopes of eventually incorporating something like this into the manpage.
+
+Note: Currently, the parser varies slightly from this, but only in
+very minor ways, e.g., the strflags maybe separated by '/' characters
+and at most one strcount is allowed; likewise for regflags.
+
+------------------------------------------------------------------------
+magic = 1*query
+
+query = line *( 1*level line )
+
+level = ">" ;; Increment the level by 1.
+ ;; The first line of a query is at level 0.
+
+line = offset HWS type HWS test HWS message EOL
+
+------------------------------------------------------------------------
+offset = absoffset | reloffset | indoffset
+ ;; The offset in the file at which to apply
+ ;; the <test>.
+
+absoffset = NUMBER ;; An absolute offset from the start of the file.
+
+reloffset = "&" NUMBER ;; The offset relative to the last match offset
+ ;; at one level up.
+ ;; Not allowed at level == 0.
+
+indoffset = indoff | relindoff
+
+indoff = "(" offset1 [ "." size ] [ op disp ] ")"
+ ;; Read the file at <offset1> of width <size>.
+ ;; If size is not specified, assume a long.
+ ;; If <op> is given, then preform that
+ ;; operation on the result and the <disp>.
+
+offset1 = absoffset | reloffset
+
+size = byte | leshort | beshort | lelong | belong | melong
+
+byte = "B" | "b" | "C" | "c" ;; A one-byte value.
+leshort = "s" | "h" ;; A two-byte little-endian value.
+beshort = "S" | "H" ;; A two-byte big-endian value.
+lelong = "l" ;; A four-byte little-endian value.
+belong = "L" ;; A four-byte big-endian value.
+melong = "m" ;; A four-byte middle-endian value.
+
+op = [ invert ] ( "+" | "-" | "*" | "/" | "%" | "&" | "|" | "^" )
+
+invert = "~" ;; Flip the bits on result of the <op>.
+
+disp = NUMBER | memvalue
+
+memvalue = "(" NUMBER ")"
+ ;; NUMBER is interpreted as an absolute or
+ ;; relative offset matching that of <offset1>.
+ ;; Read the file at the resulting offset with
+ ;; the same size as <offset1>
+
+relindoff = "&" indoff ;; add <indoff> to the last match offset at
+ ;; one level up.
+
+------------------------------------------------------------------------
+type = [ unsigned ] ( numeric | strtype | default )
+
+unsigned = "u" ;; The value is unsigned.
+ ;; This affects the sign extension of numeric
+ ;; types and the '<' and '>' compares. It is
+ ;; intended for numeric types, but allowed on
+ ;; all types.
+
+numeric = ( numtype | datatype ) [ nummask ]
+
+numtype = byte | short | long | quad
+
+byte = "byte"
+short = "short" | "beshort" | "leshort"
+long = "long" | "lelong" | "belong" | "melong"
+quad = "quad" | "lequad" | "bequad"
+
+datetype = udate32 | ldate32 | udate64 | ldate64
+
+udate32 = "date" | "bedate" | "ledate" | "medate" ;; UTC dates
+ldate32 = "ldate" | "beldate" | "leldate" | "meldate" ;; local dates
+udate64 = "qdate" | "leqdate" | "beqdate" ;; UTC dates
+ldate64 = "qldate" | "leqldate" | "beqldate" ;; local dates
+
+nummask = op NUMBER
+
+strtype = regex | search | string8 | string16
+
+regex = "regex" [ "/" 1*regflag ]
+
+regflag = "c" | "s" | linecnt
+
+linecnt = NUMBER ;; The number of lines to search. If this
+ ;; is missing or zero, the rest of the
+ ;; file is searched.
+
+search = "string" [ "/" 1*srchflag ]
+
+srchflag = strflag | srchcnt
+
+srchcnt = NUMBER ;; The number of search tries. If this
+ ;; is missing or zero, the rest of the
+ ;; file is searched.
+
+string8 = ( "string" | "pstring" ) [ "/" 1*strflag ]
+
+strflag = "b" | "B" | "c" | "C"
+
+string16 = "bestring16" | "lestring16"
+
+default = "default" ;; This is intended to be used with the
+ ;; <truetest> ("x" below). It is matched if
+ ;; there has been no previous match at its
+ ;; level or none since the last default at
+ ;; that level. It is useful for implementing
+ ;; switch-like and if/else constructions.
+
+------------------------------------------------------------------------
+test = numtest | strtest | truetest
+ ;; Test to preform on <type> read from file.
+
+numtest = [ compare ] NUMBER ;; If compare is missing, "=" is assumed.
+
+strtest = [ compare ] STRING ;; If compare is missing, "=" is assumed.
+ ;; Note: If the STRING begins with a <compare>
+ ;; character, the <compare> field cannot be
+ ;; omitted.
+
+compare = "=" | "!" | "<" | ">" | "&" | "^"
+
+truetest = "x" ;; This always returns true.
+ ;; To test for the string "x" use "=x".
+
+------------------------------------------------------------------------
+message = [ nospflag ] ( STRING | FMT_STRING )
+ ;; Message to print if test result is true.
+
+nospflag = %x08 | "\\b" ;; Do not insert a space before the message.
+ ;; By default, messages are separated by a " ".
+
+------------------------------------------------------------------------
+HWS = <horizontal white space>
+EOL = <end of line marker>
+NUMBER = <C-style unsigned number>
+STRING = <C-style string without delimiting quotes>
+FMTSTR = <printf format string with exactly one % construct>
+
+------------------------------------------------------------------------
diff --git a/node_modules/mmmagic/deps/libmagic/src/apprentice.c b/node_modules/mmmagic/deps/libmagic/src/apprentice.c
new file mode 100644
index 0000000..8197f65
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/apprentice.c
@@ -0,0 +1,3429 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * apprentice - make one pass through /etc/magic, learning its secrets.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: apprentice.c,v 1.262 2017/08/28 13:39:18 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifdef QUICK
+#include <sys/mman.h>
+#endif
+// XXX: change by mscdex
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#if defined(HAVE_LIMITS_H)
+#include <limits.h>
+#endif
+
+#ifndef SSIZE_MAX
+#define MAXMAGIC_SIZE ((ssize_t)0x7fffffff)
+#else
+#define MAXMAGIC_SIZE SSIZE_MAX
+#endif
+
+#define EATAB {while (isascii((unsigned char) *l) && \
+ isspace((unsigned char) *l)) ++l;}
+#define LOWCASE(l) (isupper((unsigned char) (l)) ? \
+ tolower((unsigned char) (l)) : (l))
+/*
+ * Work around a bug in headers on Digital Unix.
+ * At least confirmed for: OSF1 V4.0 878
+ */
+#if defined(__osf__) && defined(__DECC)
+#ifdef MAP_FAILED
+#undef MAP_FAILED
+#endif
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED (void *) -1
+#endif
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+#define ALLOC_CHUNK (size_t)10
+#define ALLOC_INCR (size_t)200
+
+#define MAP_TYPE_USER 0
+#define MAP_TYPE_MALLOC 1
+#define MAP_TYPE_MMAP 2
+
+struct magic_entry {
+ struct magic *mp;
+ uint32_t cont_count;
+ uint32_t max_count;
+};
+
+struct magic_entry_set {
+ struct magic_entry *me;
+ uint32_t count;
+ uint32_t max;
+};
+
+struct magic_map {
+ void *p;
+ size_t len;
+ int type;
+ struct magic *magic[MAGIC_SETS];
+ uint32_t nmagic[MAGIC_SETS];
+};
+
+int file_formats[FILE_NAMES_SIZE];
+const size_t file_nformats = FILE_NAMES_SIZE;
+const char *file_names[FILE_NAMES_SIZE];
+const size_t file_nnames = FILE_NAMES_SIZE;
+
+private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
+private int hextoint(int);
+private const char *getstr(struct magic_set *, struct magic *, const char *,
+ int);
+private int parse(struct magic_set *, struct magic_entry *, const char *,
+ size_t, int);
+private void eatsize(const char **);
+private int apprentice_1(struct magic_set *, const char *, int);
+private size_t apprentice_magic_strength(const struct magic *);
+private int apprentice_sort(const void *, const void *);
+private void apprentice_list(struct mlist *, int );
+private struct magic_map *apprentice_load(struct magic_set *,
+ const char *, int);
+private struct mlist *mlist_alloc(void);
+private void mlist_free(struct mlist *);
+private void byteswap(struct magic *, uint32_t);
+private void bs1(struct magic *);
+private uint16_t swap2(uint16_t);
+private uint32_t swap4(uint32_t);
+private uint64_t swap8(uint64_t);
+private char *mkdbname(struct magic_set *, const char *, int);
+private struct magic_map *apprentice_buf(struct magic_set *, struct magic *,
+ size_t);
+private struct magic_map *apprentice_map(struct magic_set *, const char *);
+private int check_buffer(struct magic_set *, struct magic_map *, const char *);
+private void apprentice_unmap(struct magic_map *);
+private int apprentice_compile(struct magic_set *, struct magic_map *,
+ const char *);
+private int check_format_type(const char *, int, const char **);
+private int check_format(struct magic_set *, struct magic *);
+private int get_op(char);
+private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
+private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
+private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
+private int parse_ext(struct magic_set *, struct magic_entry *, const char *);
+
+
+private size_t magicsize = sizeof(struct magic);
+
+private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
+
+private struct {
+ const char *name;
+ size_t len;
+ int (*fun)(struct magic_set *, struct magic_entry *, const char *);
+} bang[] = {
+#define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
+ DECLARE_FIELD(mime),
+ DECLARE_FIELD(apple),
+ DECLARE_FIELD(ext),
+ DECLARE_FIELD(strength),
+#undef DECLARE_FIELD
+ { NULL, 0, NULL }
+};
+
+#ifdef COMPILE_ONLY
+
+int main(int, char *[]);
+
+int
+main(int argc, char *argv[])
+{
+ int ret;
+ struct magic_set *ms;
+ char *progname;
+
+ if ((progname = strrchr(argv[0], '/')) != NULL)
+ progname++;
+ else
+ progname = argv[0];
+
+ if (argc != 2) {
+ (void)fprintf(stderr, "Usage: %s file\n", progname);
+ return 1;
+ }
+
+ if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
+ (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+ return 1;
+ }
+ ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
+ if (ret == 1)
+ (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
+ magic_close(ms);
+ return ret;
+}
+#endif /* COMPILE_ONLY */
+
+struct type_tbl_s {
+ const char name[16];
+ const size_t len;
+ const int type;
+ const int format;
+};
+
+/*
+ * XXX - the actual Single UNIX Specification says that "long" means "long",
+ * as in the C data type, but we treat it as meaning "4-byte integer".
+ * Given that the OS X version of file 5.04 did the same, I guess that passes
+ * the actual test; having "long" be dependent on how big a "long" is on
+ * the machine running "file" is silly.
+ */
+static const struct type_tbl_s type_tbl[] = {
+# define XX(s) s, (sizeof(s) - 1)
+# define XX_NULL "", 0
+ { XX("invalid"), FILE_INVALID, FILE_FMT_NONE },
+ { XX("byte"), FILE_BYTE, FILE_FMT_NUM },
+ { XX("short"), FILE_SHORT, FILE_FMT_NUM },
+ { XX("default"), FILE_DEFAULT, FILE_FMT_NONE },
+ { XX("long"), FILE_LONG, FILE_FMT_NUM },
+ { XX("string"), FILE_STRING, FILE_FMT_STR },
+ { XX("date"), FILE_DATE, FILE_FMT_STR },
+ { XX("beshort"), FILE_BESHORT, FILE_FMT_NUM },
+ { XX("belong"), FILE_BELONG, FILE_FMT_NUM },
+ { XX("bedate"), FILE_BEDATE, FILE_FMT_STR },
+ { XX("leshort"), FILE_LESHORT, FILE_FMT_NUM },
+ { XX("lelong"), FILE_LELONG, FILE_FMT_NUM },
+ { XX("ledate"), FILE_LEDATE, FILE_FMT_STR },
+ { XX("pstring"), FILE_PSTRING, FILE_FMT_STR },
+ { XX("ldate"), FILE_LDATE, FILE_FMT_STR },
+ { XX("beldate"), FILE_BELDATE, FILE_FMT_STR },
+ { XX("leldate"), FILE_LELDATE, FILE_FMT_STR },
+ { XX("regex"), FILE_REGEX, FILE_FMT_STR },
+ { XX("bestring16"), FILE_BESTRING16, FILE_FMT_STR },
+ { XX("lestring16"), FILE_LESTRING16, FILE_FMT_STR },
+ { XX("search"), FILE_SEARCH, FILE_FMT_STR },
+ { XX("medate"), FILE_MEDATE, FILE_FMT_STR },
+ { XX("meldate"), FILE_MELDATE, FILE_FMT_STR },
+ { XX("melong"), FILE_MELONG, FILE_FMT_NUM },
+ { XX("quad"), FILE_QUAD, FILE_FMT_QUAD },
+ { XX("lequad"), FILE_LEQUAD, FILE_FMT_QUAD },
+ { XX("bequad"), FILE_BEQUAD, FILE_FMT_QUAD },
+ { XX("qdate"), FILE_QDATE, FILE_FMT_STR },
+ { XX("leqdate"), FILE_LEQDATE, FILE_FMT_STR },
+ { XX("beqdate"), FILE_BEQDATE, FILE_FMT_STR },
+ { XX("qldate"), FILE_QLDATE, FILE_FMT_STR },
+ { XX("leqldate"), FILE_LEQLDATE, FILE_FMT_STR },
+ { XX("beqldate"), FILE_BEQLDATE, FILE_FMT_STR },
+ { XX("float"), FILE_FLOAT, FILE_FMT_FLOAT },
+ { XX("befloat"), FILE_BEFLOAT, FILE_FMT_FLOAT },
+ { XX("lefloat"), FILE_LEFLOAT, FILE_FMT_FLOAT },
+ { XX("double"), FILE_DOUBLE, FILE_FMT_DOUBLE },
+ { XX("bedouble"), FILE_BEDOUBLE, FILE_FMT_DOUBLE },
+ { XX("ledouble"), FILE_LEDOUBLE, FILE_FMT_DOUBLE },
+ { XX("leid3"), FILE_LEID3, FILE_FMT_NUM },
+ { XX("beid3"), FILE_BEID3, FILE_FMT_NUM },
+ { XX("indirect"), FILE_INDIRECT, FILE_FMT_NUM },
+ { XX("qwdate"), FILE_QWDATE, FILE_FMT_STR },
+ { XX("leqwdate"), FILE_LEQWDATE, FILE_FMT_STR },
+ { XX("beqwdate"), FILE_BEQWDATE, FILE_FMT_STR },
+ { XX("name"), FILE_NAME, FILE_FMT_NONE },
+ { XX("use"), FILE_USE, FILE_FMT_NONE },
+ { XX("clear"), FILE_CLEAR, FILE_FMT_NONE },
+ { XX("der"), FILE_DER, FILE_FMT_STR },
+ { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
+};
+
+/*
+ * These are not types, and cannot be preceded by "u" to make them
+ * unsigned.
+ */
+static const struct type_tbl_s special_tbl[] = {
+ { XX("der"), FILE_DER, FILE_FMT_STR },
+ { XX("name"), FILE_NAME, FILE_FMT_STR },
+ { XX("use"), FILE_USE, FILE_FMT_STR },
+ { XX_NULL, FILE_INVALID, FILE_FMT_NONE },
+};
+# undef XX
+# undef XX_NULL
+
+private int
+get_type(const struct type_tbl_s *tbl, const char *l, const char **t)
+{
+ const struct type_tbl_s *p;
+
+ for (p = tbl; p->len; p++) {
+ if (strncmp(l, p->name, p->len) == 0) {
+ if (t)
+ *t = l + p->len;
+ break;
+ }
+ }
+ return p->type;
+}
+
+private int
+get_standard_integer_type(const char *l, const char **t)
+{
+ int type;
+
+ if (isalpha((unsigned char)l[1])) {
+ switch (l[1]) {
+ case 'C':
+ /* "dC" and "uC" */
+ type = FILE_BYTE;
+ break;
+ case 'S':
+ /* "dS" and "uS" */
+ type = FILE_SHORT;
+ break;
+ case 'I':
+ case 'L':
+ /*
+ * "dI", "dL", "uI", and "uL".
+ *
+ * XXX - the actual Single UNIX Specification says
+ * that "L" means "long", as in the C data type,
+ * but we treat it as meaning "4-byte integer".
+ * Given that the OS X version of file 5.04 did
+ * the same, I guess that passes the actual SUS
+ * validation suite; having "dL" be dependent on
+ * how big a "long" is on the machine running
+ * "file" is silly.
+ */
+ type = FILE_LONG;
+ break;
+ case 'Q':
+ /* "dQ" and "uQ" */
+ type = FILE_QUAD;
+ break;
+ default:
+ /* "d{anything else}", "u{anything else}" */
+ return FILE_INVALID;
+ }
+ l += 2;
+ } else if (isdigit((unsigned char)l[1])) {
+ /*
+ * "d{num}" and "u{num}"; we only support {num} values
+ * of 1, 2, 4, and 8 - the Single UNIX Specification
+ * doesn't say anything about whether arbitrary
+ * values should be supported, but both the Solaris 10
+ * and OS X Mountain Lion versions of file passed the
+ * Single UNIX Specification validation suite, and
+ * neither of them support values bigger than 8 or
+ * non-power-of-2 values.
+ */
+ if (isdigit((unsigned char)l[2])) {
+ /* Multi-digit, so > 9 */
+ return FILE_INVALID;
+ }
+ switch (l[1]) {
+ case '1':
+ type = FILE_BYTE;
+ break;
+ case '2':
+ type = FILE_SHORT;
+ break;
+ case '4':
+ type = FILE_LONG;
+ break;
+ case '8':
+ type = FILE_QUAD;
+ break;
+ default:
+ /* XXX - what about 3, 5, 6, or 7? */
+ return FILE_INVALID;
+ }
+ l += 2;
+ } else {
+ /*
+ * "d" or "u" by itself.
+ */
+ type = FILE_LONG;
+ ++l;
+ }
+ if (t)
+ *t = l;
+ return type;
+}
+
+private void
+init_file_tables(void)
+{
+ static int done = 0;
+ const struct type_tbl_s *p;
+
+ if (done)
+ return;
+ done++;
+
+ for (p = type_tbl; p->len; p++) {
+ assert(p->type < FILE_NAMES_SIZE);
+ file_names[p->type] = p->name;
+ file_formats[p->type] = p->format;
+ }
+ assert(p - type_tbl == FILE_NAMES_SIZE);
+}
+
+private int
+add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx)
+{
+ struct mlist *ml;
+
+ mlp->map = NULL;
+ if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL)
+ return -1;
+
+ ml->map = idx == 0 ? map : NULL;
+ ml->magic = map->magic[idx];
+ ml->nmagic = map->nmagic[idx];
+
+ mlp->prev->next = ml;
+ ml->prev = mlp->prev;
+ ml->next = mlp;
+ mlp->prev = ml;
+ return 0;
+}
+
+/*
+ * Handle one file or directory.
+ */
+private int
+apprentice_1(struct magic_set *ms, const char *fn, int action)
+{
+ struct magic_map *map;
+#ifndef COMPILE_ONLY
+ struct mlist *ml;
+ size_t i;
+#endif
+
+ if (magicsize != FILE_MAGICSIZE) {
+ file_error(ms, 0, "magic element size %lu != %lu",
+ (unsigned long)sizeof(*map->magic[0]),
+ (unsigned long)FILE_MAGICSIZE);
+ return -1;
+ }
+
+ if (action == FILE_COMPILE) {
+ map = apprentice_load(ms, fn, action);
+ if (map == NULL)
+ return -1;
+ return apprentice_compile(ms, map, fn);
+ }
+
+#ifndef COMPILE_ONLY
+ map = apprentice_map(ms, fn);
+ if (map == (struct magic_map *)-1)
+ return -1;
+ if (map == NULL) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "using regular magic file `%s'", fn);
+ map = apprentice_load(ms, fn, action);
+ if (map == NULL)
+ return -1;
+ }
+
+ for (i = 0; i < MAGIC_SETS; i++) {
+ if (add_mlist(ms->mlist[i], map, i) == -1) {
+ file_oomem(ms, sizeof(*ml));
+ return -1;
+ }
+ }
+
+ if (action == FILE_LIST) {
+ for (i = 0; i < MAGIC_SETS; i++) {
+ printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n",
+ i);
+ apprentice_list(ms->mlist[i], BINTEST);
+ printf("Text patterns:\n");
+ apprentice_list(ms->mlist[i], TEXTTEST);
+ }
+ }
+ return 0;
+#else
+ return 0;
+#endif /* COMPILE_ONLY */
+}
+
+protected void
+file_ms_free(struct magic_set *ms)
+{
+ size_t i;
+ if (ms == NULL)
+ return;
+ for (i = 0; i < MAGIC_SETS; i++)
+ mlist_free(ms->mlist[i]);
+ free(ms->o.pbuf);
+ free(ms->o.buf);
+ free(ms->c.li);
+ free(ms);
+}
+
+protected struct magic_set *
+file_ms_alloc(int flags)
+{
+ struct magic_set *ms;
+ size_t i, len;
+
+ if ((ms = CAST(struct magic_set *, calloc((size_t)1,
+ sizeof(struct magic_set)))) == NULL)
+ return NULL;
+
+ if (magic_setflags(ms, flags) == -1) {
+ errno = EINVAL;
+ goto free;
+ }
+
+ ms->o.buf = ms->o.pbuf = NULL;
+ len = (ms->c.len = 10) * sizeof(*ms->c.li);
+
+ if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL)
+ goto free;
+
+ ms->event_flags = 0;
+ ms->error = -1;
+ for (i = 0; i < MAGIC_SETS; i++)
+ ms->mlist[i] = NULL;
+ ms->file = "unknown";
+ ms->line = 0;
+ ms->indir_max = FILE_INDIR_MAX;
+ ms->name_max = FILE_NAME_MAX;
+ ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
+ ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
+ ms->elf_notes_max = FILE_ELF_NOTES_MAX;
+ ms->regex_max = FILE_REGEX_MAX;
+ ms->bytes_max = FILE_BYTES_MAX;
+ return ms;
+free:
+ free(ms);
+ return NULL;
+}
+
+private void
+apprentice_unmap(struct magic_map *map)
+{
+ size_t i;
+ if (map == NULL)
+ return;
+
+ switch (map->type) {
+ case MAP_TYPE_USER:
+ break;
+ case MAP_TYPE_MALLOC:
+ for (i = 0; i < MAGIC_SETS; i++) {
+ void *b = map->magic[i];
+ void *p = map->p;
+ if (CAST(char *, b) >= CAST(char *, p) &&
+ CAST(char *, b) <= CAST(char *, p) + map->len)
+ continue;
+ free(map->magic[i]);
+ }
+ free(map->p);
+ break;
+#ifdef QUICK
+ case MAP_TYPE_MMAP:
+ if (map->p && map->p != MAP_FAILED)
+ (void)munmap(map->p, map->len);
+ break;
+#endif
+ default:
+ abort();
+ }
+ free(map);
+}
+
+private struct mlist *
+mlist_alloc(void)
+{
+ struct mlist *mlist;
+ if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) {
+ return NULL;
+ }
+ mlist->next = mlist->prev = mlist;
+ return mlist;
+}
+
+private void
+mlist_free(struct mlist *mlist)
+{
+ struct mlist *ml, *next;
+
+ if (mlist == NULL)
+ return;
+
+ ml = mlist->next;
+ for (ml = mlist->next; (next = ml->next) != NULL; ml = next) {
+ if (ml->map)
+ apprentice_unmap(CAST(struct magic_map *, ml->map));
+ free(ml);
+ if (ml == mlist)
+ break;
+ }
+}
+
+#ifndef COMPILE_ONLY
+/* void **bufs: an array of compiled magic files */
+protected int
+buffer_apprentice(struct magic_set *ms, struct magic **bufs,
+ size_t *sizes, size_t nbufs)
+{
+ size_t i, j;
+ struct mlist *ml;
+ struct magic_map *map;
+
+ if (nbufs == 0)
+ return -1;
+
+ (void)file_reset(ms, 0);
+
+ init_file_tables();
+
+ for (i = 0; i < MAGIC_SETS; i++) {
+ mlist_free(ms->mlist[i]);
+ if ((ms->mlist[i] = mlist_alloc()) == NULL) {
+ file_oomem(ms, sizeof(*ms->mlist[i]));
+ goto fail;
+ }
+ }
+
+ for (i = 0; i < nbufs; i++) {
+ map = apprentice_buf(ms, bufs[i], sizes[i]);
+ if (map == NULL)
+ goto fail;
+
+ for (j = 0; j < MAGIC_SETS; j++) {
+ if (add_mlist(ms->mlist[j], map, j) == -1) {
+ file_oomem(ms, sizeof(*ml));
+ goto fail;
+ }
+ }
+ }
+
+ return 0;
+fail:
+ for (i = 0; i < MAGIC_SETS; i++) {
+ mlist_free(ms->mlist[i]);
+ ms->mlist[i] = NULL;
+ }
+ return -1;
+}
+#endif
+
+/* const char *fn: list of magic files and directories */
+protected int
+file_apprentice(struct magic_set *ms, const char *fn, int action)
+{
+ char *p, *mfn;
+ int file_err, errs = -1;
+ size_t i;
+
+ (void)file_reset(ms, 0);
+
+ if ((fn = magic_getpath(fn, action)) == NULL)
+ return -1;
+
+ init_file_tables();
+
+ if ((mfn = strdup(fn)) == NULL) {
+ file_oomem(ms, strlen(fn));
+ return -1;
+ }
+
+ for (i = 0; i < MAGIC_SETS; i++) {
+ mlist_free(ms->mlist[i]);
+ if ((ms->mlist[i] = mlist_alloc()) == NULL) {
+ file_oomem(ms, sizeof(*ms->mlist[i]));
+ while (i-- > 0) {
+ mlist_free(ms->mlist[i]);
+ ms->mlist[i] = NULL;
+ }
+ free(mfn);
+ return -1;
+ }
+ }
+ fn = mfn;
+
+ while (fn) {
+ p = strchr(fn, PATHSEP);
+ if (p)
+ *p++ = '\0';
+ if (*fn == '\0')
+ break;
+ file_err = apprentice_1(ms, fn, action);
+ errs = MAX(errs, file_err);
+ fn = p;
+ }
+
+ free(mfn);
+
+ if (errs == -1) {
+ for (i = 0; i < MAGIC_SETS; i++) {
+ mlist_free(ms->mlist[i]);
+ ms->mlist[i] = NULL;
+ }
+ // XXX: change by mscdex
+ file_error(ms, 0, "could not load any valid magic files!");
+ return -1;
+ }
+
+#if 0
+ /*
+ * Always leave the database loaded
+ */
+ if (action == FILE_LOAD)
+ return 0;
+
+ for (i = 0; i < MAGIC_SETS; i++) {
+ mlist_free(ms->mlist[i]);
+ ms->mlist[i] = NULL;
+ }
+#endif
+
+ switch (action) {
+ case FILE_LOAD:
+ case FILE_COMPILE:
+ case FILE_CHECK:
+ case FILE_LIST:
+ return 0;
+ default:
+ file_error(ms, 0, "Invalid action %d", action);
+ return -1;
+ }
+}
+
+/*
+ * Compute the real length of a magic expression, for the purposes
+ * of determining how "strong" a magic expression is (approximating
+ * how specific its matches are):
+ * - magic characters count 0 unless escaped.
+ * - [] expressions count 1
+ * - {} expressions count 0
+ * - regular characters or escaped magic characters count 1
+ * - 0 length expressions count as one
+ */
+private size_t
+nonmagic(const char *str)
+{
+ const char *p;
+ size_t rv = 0;
+
+ for (p = str; *p; p++)
+ switch (*p) {
+ case '\\': /* Escaped anything counts 1 */
+ if (!*++p)
+ p--;
+ rv++;
+ continue;
+ case '?': /* Magic characters count 0 */
+ case '*':
+ case '.':
+ case '+':
+ case '^':
+ case '$':
+ continue;
+ case '[': /* Bracketed expressions count 1 the ']' */
+ while (*p && *p != ']')
+ p++;
+ p--;
+ continue;
+ case '{': /* Braced expressions count 0 */
+ while (*p && *p != '}')
+ p++;
+ if (!*p)
+ p--;
+ continue;
+ default: /* Anything else counts 1 */
+ rv++;
+ continue;
+ }
+
+ return rv == 0 ? 1 : rv; /* Return at least 1 */
+}
+
+
+private size_t
+typesize(int type)
+{
+ switch (type) {
+ case FILE_BYTE:
+ return 1;
+
+ case FILE_SHORT:
+ case FILE_LESHORT:
+ case FILE_BESHORT:
+ return 2;
+
+ case FILE_LONG:
+ case FILE_LELONG:
+ case FILE_BELONG:
+ case FILE_MELONG:
+ return 4;
+
+ case FILE_DATE:
+ case FILE_LEDATE:
+ case FILE_BEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_LELDATE:
+ case FILE_BELDATE:
+ case FILE_MELDATE:
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ return 4;
+
+ case FILE_QUAD:
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ case FILE_QDATE:
+ case FILE_LEQDATE:
+ case FILE_BEQDATE:
+ case FILE_QLDATE:
+ case FILE_LEQLDATE:
+ case FILE_BEQLDATE:
+ case FILE_QWDATE:
+ case FILE_LEQWDATE:
+ case FILE_BEQWDATE:
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ return 8;
+ default:
+ return (size_t)~0;
+ }
+}
+
+/*
+ * Get weight of this magic entry, for sorting purposes.
+ */
+private size_t
+apprentice_magic_strength(const struct magic *m)
+{
+#define MULT 10
+ size_t ts, v, val = 2 * MULT; /* baseline strength */
+
+ switch (m->type) {
+ case FILE_DEFAULT: /* make sure this sorts last */
+ if (m->factor_op != FILE_FACTOR_OP_NONE)
+ abort();
+ return 0;
+
+ case FILE_BYTE:
+ case FILE_SHORT:
+ case FILE_LESHORT:
+ case FILE_BESHORT:
+ case FILE_LONG:
+ case FILE_LELONG:
+ case FILE_BELONG:
+ case FILE_MELONG:
+ case FILE_DATE:
+ case FILE_LEDATE:
+ case FILE_BEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_LELDATE:
+ case FILE_BELDATE:
+ case FILE_MELDATE:
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ case FILE_QUAD:
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ case FILE_QDATE:
+ case FILE_LEQDATE:
+ case FILE_BEQDATE:
+ case FILE_QLDATE:
+ case FILE_LEQLDATE:
+ case FILE_BEQLDATE:
+ case FILE_QWDATE:
+ case FILE_LEQWDATE:
+ case FILE_BEQWDATE:
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ ts = typesize(m->type);
+ if (ts == (size_t)~0)
+ abort();
+ val += ts * MULT;
+ break;
+
+ case FILE_PSTRING:
+ case FILE_STRING:
+ val += m->vallen * MULT;
+ break;
+
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ val += m->vallen * MULT / 2;
+ break;
+
+ case FILE_SEARCH:
+ val += m->vallen * MAX(MULT / m->vallen, 1);
+ break;
+
+ case FILE_REGEX:
+ v = nonmagic(m->value.s);
+ val += v * MAX(MULT / v, 1);
+ break;
+
+ case FILE_INDIRECT:
+ case FILE_NAME:
+ case FILE_USE:
+ break;
+
+ case FILE_DER:
+ val += MULT;
+ break;
+
+ default:
+ (void)fprintf(stderr, "Bad type %d\n", m->type);
+ abort();
+ }
+
+ switch (m->reln) {
+ case 'x': /* matches anything penalize */
+ case '!': /* matches almost anything penalize */
+ val = 0;
+ break;
+
+ case '=': /* Exact match, prefer */
+ val += MULT;
+ break;
+
+ case '>':
+ case '<': /* comparison match reduce strength */
+ val -= 2 * MULT;
+ break;
+
+ case '^':
+ case '&': /* masking bits, we could count them too */
+ val -= MULT;
+ break;
+
+ default:
+ (void)fprintf(stderr, "Bad relation %c\n", m->reln);
+ abort();
+ }
+
+ if (val == 0) /* ensure we only return 0 for FILE_DEFAULT */
+ val = 1;
+
+ switch (m->factor_op) {
+ case FILE_FACTOR_OP_NONE:
+ break;
+ case FILE_FACTOR_OP_PLUS:
+ val += m->factor;
+ break;
+ case FILE_FACTOR_OP_MINUS:
+ val -= m->factor;
+ break;
+ case FILE_FACTOR_OP_TIMES:
+ val *= m->factor;
+ break;
+ case FILE_FACTOR_OP_DIV:
+ val /= m->factor;
+ break;
+ default:
+ abort();
+ }
+
+ /*
+ * Magic entries with no description get a bonus because they depend
+ * on subsequent magic entries to print something.
+ */
+ if (m->desc[0] == '\0')
+ val++;
+ return val;
+}
+
+/*
+ * Sort callback for sorting entries by "strength" (basically length)
+ */
+private int
+apprentice_sort(const void *a, const void *b)
+{
+ const struct magic_entry *ma = CAST(const struct magic_entry *, a);
+ const struct magic_entry *mb = CAST(const struct magic_entry *, b);
+ size_t sa = apprentice_magic_strength(ma->mp);
+ size_t sb = apprentice_magic_strength(mb->mp);
+ if (sa == sb)
+ return 0;
+ else if (sa > sb)
+ return -1;
+ else
+ return 1;
+}
+
+/*
+ * Shows sorted patterns list in the order which is used for the matching
+ */
+private void
+apprentice_list(struct mlist *mlist, int mode)
+{
+ uint32_t magindex = 0;
+ struct mlist *ml;
+ for (ml = mlist->next; ml != mlist; ml = ml->next) {
+ for (magindex = 0; magindex < ml->nmagic; magindex++) {
+ struct magic *m = &ml->magic[magindex];
+ if ((m->flag & mode) != mode) {
+ /* Skip sub-tests */
+ while (magindex + 1 < ml->nmagic &&
+ ml->magic[magindex + 1].cont_level != 0)
+ ++magindex;
+ continue; /* Skip to next top-level test*/
+ }
+
+ /*
+ * Try to iterate over the tree until we find item with
+ * description/mimetype.
+ */
+ while (magindex + 1 < ml->nmagic &&
+ ml->magic[magindex + 1].cont_level != 0 &&
+ *ml->magic[magindex].desc == '\0' &&
+ *ml->magic[magindex].mimetype == '\0')
+ magindex++;
+
+ printf("Strength = %3" SIZE_T_FORMAT "u@%u: %s [%s]\n",
+ apprentice_magic_strength(m),
+ ml->magic[magindex].lineno,
+ ml->magic[magindex].desc,
+ ml->magic[magindex].mimetype);
+ }
+ }
+}
+
+private void
+set_test_type(struct magic *mstart, struct magic *m)
+{
+ switch (m->type) {
+ case FILE_BYTE:
+ case FILE_SHORT:
+ case FILE_LONG:
+ case FILE_DATE:
+ case FILE_BESHORT:
+ case FILE_BELONG:
+ case FILE_BEDATE:
+ case FILE_LESHORT:
+ case FILE_LELONG:
+ case FILE_LEDATE:
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MEDATE:
+ case FILE_MELDATE:
+ case FILE_MELONG:
+ case FILE_QUAD:
+ case FILE_LEQUAD:
+ case FILE_BEQUAD:
+ case FILE_QDATE:
+ case FILE_LEQDATE:
+ case FILE_BEQDATE:
+ case FILE_QLDATE:
+ case FILE_LEQLDATE:
+ case FILE_BEQLDATE:
+ case FILE_QWDATE:
+ case FILE_LEQWDATE:
+ case FILE_BEQWDATE:
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ case FILE_DER:
+ mstart->flag |= BINTEST;
+ break;
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ /* Allow text overrides */
+ if (mstart->str_flags & STRING_TEXTTEST)
+ mstart->flag |= TEXTTEST;
+ else
+ mstart->flag |= BINTEST;
+ break;
+ case FILE_REGEX:
+ case FILE_SEARCH:
+ /* Check for override */
+ if (mstart->str_flags & STRING_BINTEST)
+ mstart->flag |= BINTEST;
+ if (mstart->str_flags & STRING_TEXTTEST)
+ mstart->flag |= TEXTTEST;
+
+ if (mstart->flag & (TEXTTEST|BINTEST))
+ break;
+
+ /* binary test if pattern is not text */
+ if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
+ NULL) <= 0)
+ mstart->flag |= BINTEST;
+ else
+ mstart->flag |= TEXTTEST;
+ break;
+ case FILE_DEFAULT:
+ /* can't deduce anything; we shouldn't see this at the
+ top level anyway */
+ break;
+ case FILE_INVALID:
+ default:
+ /* invalid search type, but no need to complain here */
+ break;
+ }
+}
+
+private int
+addentry(struct magic_set *ms, struct magic_entry *me,
+ struct magic_entry_set *mset)
+{
+ size_t i = me->mp->type == FILE_NAME ? 1 : 0;
+ if (mset[i].count == mset[i].max) {
+ struct magic_entry *mp;
+
+ mset[i].max += ALLOC_INCR;
+ if ((mp = CAST(struct magic_entry *,
+ realloc(mset[i].me, sizeof(*mp) * mset[i].max))) ==
+ NULL) {
+ file_oomem(ms, sizeof(*mp) * mset[i].max);
+ return -1;
+ }
+ (void)memset(&mp[mset[i].count], 0, sizeof(*mp) *
+ ALLOC_INCR);
+ mset[i].me = mp;
+ }
+ mset[i].me[mset[i].count++] = *me;
+ memset(me, 0, sizeof(*me));
+ return 0;
+}
+
+/*
+ * Load and parse one file.
+ */
+private void
+load_1(struct magic_set *ms, int action, const char *fn, int *errs,
+ struct magic_entry_set *mset)
+{
+ size_t lineno = 0, llen = 0;
+ char *line = NULL;
+ ssize_t len;
+ struct magic_entry me;
+
+ FILE *f = fopen(ms->file = fn, "r");
+ if (f == NULL) {
+ if (errno != ENOENT)
+ file_error(ms, errno, "cannot read magic file `%s'",
+ fn);
+ (*errs)++;
+ return;
+ }
+
+ memset(&me, 0, sizeof(me));
+ /* read and parse this file */
+ for (ms->line = 1; (len = getline(&line, &llen, f)) != -1;
+ ms->line++) {
+ if (len == 0) /* null line, garbage, etc */
+ continue;
+ if (line[len - 1] == '\n') {
+ lineno++;
+ line[len - 1] = '\0'; /* delete newline */
+ }
+ switch (line[0]) {
+ case '\0': /* empty, do not parse */
+ case '#': /* comment, do not parse */
+ continue;
+ case '!':
+ if (line[1] == ':') {
+ size_t i;
+
+ for (i = 0; bang[i].name != NULL; i++) {
+ if ((size_t)(len - 2) > bang[i].len &&
+ memcmp(bang[i].name, line + 2,
+ bang[i].len) == 0)
+ break;
+ }
+ if (bang[i].name == NULL) {
+ file_error(ms, 0,
+ "Unknown !: entry `%s'", line);
+ (*errs)++;
+ continue;
+ }
+ if (me.mp == NULL) {
+ file_error(ms, 0,
+ "No current entry for :!%s type",
+ bang[i].name);
+ (*errs)++;
+ continue;
+ }
+ if ((*bang[i].fun)(ms, &me,
+ line + bang[i].len + 2) != 0) {
+ (*errs)++;
+ continue;
+ }
+ continue;
+ }
+ /*FALLTHROUGH*/
+ default:
+ again:
+ switch (parse(ms, &me, line, lineno, action)) {
+ case 0:
+ continue;
+ case 1:
+ (void)addentry(ms, &me, mset);
+ goto again;
+ default:
+ (*errs)++;
+ break;
+ }
+ }
+ }
+ if (me.mp)
+ (void)addentry(ms, &me, mset);
+ free(line);
+ (void)fclose(f);
+}
+
+/*
+ * parse a file or directory of files
+ * const char *fn: name of magic file or directory
+ */
+private int
+cmpstrp(const void *p1, const void *p2)
+{
+ return strcmp(*(char *const *)p1, *(char *const *)p2);
+}
+
+
+private uint32_t
+set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
+ uint32_t starttest)
+{
+ static const char text[] = "text";
+ static const char binary[] = "binary";
+ static const size_t len = sizeof(text);
+
+ uint32_t i = starttest;
+
+ do {
+ set_test_type(me[starttest].mp, me[i].mp);
+ if ((ms->flags & MAGIC_DEBUG) == 0)
+ continue;
+ (void)fprintf(stderr, "%s%s%s: %s\n",
+ me[i].mp->mimetype,
+ me[i].mp->mimetype[0] == '\0' ? "" : "; ",
+ me[i].mp->desc[0] ? me[i].mp->desc : "(no description)",
+ me[i].mp->flag & BINTEST ? binary : text);
+ if (me[i].mp->flag & BINTEST) {
+ char *p = strstr(me[i].mp->desc, text);
+ if (p && (p == me[i].mp->desc ||
+ isspace((unsigned char)p[-1])) &&
+ (p + len - me[i].mp->desc == MAXstring
+ || (p[len] == '\0' ||
+ isspace((unsigned char)p[len]))))
+ (void)fprintf(stderr, "*** Possible "
+ "binary test for text type\n");
+ }
+ } while (++i < nme && me[i].mp->cont_level != 0);
+ return i;
+}
+
+private void
+set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme)
+{
+ uint32_t i;
+ for (i = 0; i < nme; i++) {
+ if (me[i].mp->cont_level == 0 &&
+ me[i].mp->type == FILE_DEFAULT) {
+ while (++i < nme)
+ if (me[i].mp->cont_level == 0)
+ break;
+ if (i != nme) {
+ /* XXX - Ugh! */
+ ms->line = me[i].mp->lineno;
+ file_magwarn(ms,
+ "level 0 \"default\" did not sort last");
+ }
+ return;
+ }
+ }
+}
+
+private int
+coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
+ struct magic **ma, uint32_t *nma)
+{
+ uint32_t i, mentrycount = 0;
+ size_t slen;
+
+ for (i = 0; i < nme; i++)
+ mentrycount += me[i].cont_count;
+
+ slen = sizeof(**ma) * mentrycount;
+ if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) {
+ file_oomem(ms, slen);
+ return -1;
+ }
+
+ mentrycount = 0;
+ for (i = 0; i < nme; i++) {
+ (void)memcpy(*ma + mentrycount, me[i].mp,
+ me[i].cont_count * sizeof(**ma));
+ mentrycount += me[i].cont_count;
+ }
+ *nma = mentrycount;
+ return 0;
+}
+
+private void
+magic_entry_free(struct magic_entry *me, uint32_t nme)
+{
+ uint32_t i;
+ if (me == NULL)
+ return;
+ for (i = 0; i < nme; i++)
+ free(me[i].mp);
+ free(me);
+}
+
+private struct magic_map *
+apprentice_load(struct magic_set *ms, const char *fn, int action)
+{
+ int errs = 0;
+ uint32_t i, j;
+ size_t files = 0, maxfiles = 0;
+ char **filearr = NULL, *mfn;
+ struct stat st;
+ struct magic_map *map;
+ struct magic_entry_set mset[MAGIC_SETS];
+ DIR *dir;
+ struct dirent *d;
+
+ memset(mset, 0, sizeof(mset));
+ // XXX: change by mscdex
+ //ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */
+
+
+ if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL)
+ {
+ file_oomem(ms, sizeof(*map));
+ return NULL;
+ }
+ map->type = MAP_TYPE_MALLOC;
+
+ /* print silly verbose header for USG compat. */
+ if (action == FILE_CHECK)
+ (void)fprintf(stderr, "%s\n", usg_hdr);
+
+ /* load directory or file */
+ if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
+ dir = opendir(fn);
+ if (!dir) {
+ errs++;
+ goto out;
+ }
+ while ((d = readdir(dir)) != NULL) {
+ if (d->d_name[0] == '.')
+ continue;
+ if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) {
+ file_oomem(ms,
+ strlen(fn) + strlen(d->d_name) + 2);
+ errs++;
+ closedir(dir);
+ goto out;
+ }
+ if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) {
+ free(mfn);
+ continue;
+ }
+ if (files >= maxfiles) {
+ size_t mlen;
+ maxfiles = (maxfiles + 1) * 2;
+ mlen = maxfiles * sizeof(*filearr);
+ if ((filearr = CAST(char **,
+ realloc(filearr, mlen))) == NULL) {
+ file_oomem(ms, mlen);
+ free(mfn);
+ closedir(dir);
+ errs++;
+ goto out;
+ }
+ }
+ filearr[files++] = mfn;
+ }
+ closedir(dir);
+ qsort(filearr, files, sizeof(*filearr), cmpstrp);
+ for (i = 0; i < files; i++) {
+ load_1(ms, action, filearr[i], &errs, mset);
+ free(filearr[i]);
+ }
+ free(filearr);
+ } else
+ load_1(ms, action, fn, &errs, mset);
+ if (errs)
+ goto out;
+
+ for (j = 0; j < MAGIC_SETS; j++) {
+ /* Set types of tests */
+ for (i = 0; i < mset[j].count; ) {
+ if (mset[j].me[i].mp->cont_level != 0) {
+ i++;
+ continue;
+ }
+ i = set_text_binary(ms, mset[j].me, mset[j].count, i);
+ }
+ if (mset[j].me)
+ qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me),
+ apprentice_sort);
+
+ /*
+ * Make sure that any level 0 "default" line is last
+ * (if one exists).
+ */
+ set_last_default(ms, mset[j].me, mset[j].count);
+
+ /* coalesce per file arrays into a single one */
+ if (coalesce_entries(ms, mset[j].me, mset[j].count,
+ &map->magic[j], &map->nmagic[j]) == -1) {
+ errs++;
+ goto out;
+ }
+ }
+
+out:
+ for (j = 0; j < MAGIC_SETS; j++)
+ magic_entry_free(mset[j].me, mset[j].count);
+
+ if (errs) {
+ apprentice_unmap(map);
+ return NULL;
+ }
+ return map;
+}
+
+/*
+ * extend the sign bit if the comparison is to be signed
+ */
+protected uint64_t
+file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
+{
+ if (!(m->flag & UNSIGNED)) {
+ switch(m->type) {
+ /*
+ * Do not remove the casts below. They are
+ * vital. When later compared with the data,
+ * the sign extension must have happened.
+ */
+ case FILE_BYTE:
+ v = (signed char) v;
+ break;
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ v = (short) v;
+ break;
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ v = (int32_t) v;
+ break;
+ case FILE_QUAD:
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ case FILE_QDATE:
+ case FILE_QLDATE:
+ case FILE_QWDATE:
+ case FILE_BEQDATE:
+ case FILE_BEQLDATE:
+ case FILE_BEQWDATE:
+ case FILE_LEQDATE:
+ case FILE_LEQLDATE:
+ case FILE_LEQWDATE:
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ v = (int64_t) v;
+ break;
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ case FILE_REGEX:
+ case FILE_SEARCH:
+ case FILE_DEFAULT:
+ case FILE_INDIRECT:
+ case FILE_NAME:
+ case FILE_USE:
+ case FILE_CLEAR:
+ case FILE_DER:
+ break;
+ default:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "cannot happen: m->type=%d\n",
+ m->type);
+ return ~0U;
+ }
+ }
+ return v;
+}
+
+private int
+string_modifier_check(struct magic_set *ms, struct magic *m)
+{
+ if ((ms->flags & MAGIC_CHECK) == 0)
+ return 0;
+
+ if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) &&
+ (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) {
+ file_magwarn(ms,
+ "'/BHhLl' modifiers are only allowed for pascal strings\n");
+ return -1;
+ }
+ switch (m->type) {
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ if (m->str_flags != 0) {
+ file_magwarn(ms,
+ "no modifiers allowed for 16-bit strings\n");
+ return -1;
+ }
+ break;
+ case FILE_STRING:
+ case FILE_PSTRING:
+ if ((m->str_flags & REGEX_OFFSET_START) != 0) {
+ file_magwarn(ms,
+ "'/%c' only allowed on regex and search\n",
+ CHAR_REGEX_OFFSET_START);
+ return -1;
+ }
+ break;
+ case FILE_SEARCH:
+ if (m->str_range == 0) {
+ file_magwarn(ms,
+ "missing range; defaulting to %d\n",
+ STRING_DEFAULT_RANGE);
+ m->str_range = STRING_DEFAULT_RANGE;
+ return -1;
+ }
+ break;
+ case FILE_REGEX:
+ if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) {
+ file_magwarn(ms, "'/%c' not allowed on regex\n",
+ CHAR_COMPACT_WHITESPACE);
+ return -1;
+ }
+ if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) {
+ file_magwarn(ms, "'/%c' not allowed on regex\n",
+ CHAR_COMPACT_OPTIONAL_WHITESPACE);
+ return -1;
+ }
+ break;
+ default:
+ file_magwarn(ms, "coding error: m->type=%d\n",
+ m->type);
+ return -1;
+ }
+ return 0;
+}
+
+private int
+get_op(char c)
+{
+ switch (c) {
+ case '&':
+ return FILE_OPAND;
+ case '|':
+ return FILE_OPOR;
+ case '^':
+ return FILE_OPXOR;
+ case '+':
+ return FILE_OPADD;
+ case '-':
+ return FILE_OPMINUS;
+ case '*':
+ return FILE_OPMULTIPLY;
+ case '/':
+ return FILE_OPDIVIDE;
+ case '%':
+ return FILE_OPMODULO;
+ default:
+ return -1;
+ }
+}
+
+#ifdef ENABLE_CONDITIONALS
+private int
+get_cond(const char *l, const char **t)
+{
+ static const struct cond_tbl_s {
+ char name[8];
+ size_t len;
+ int cond;
+ } cond_tbl[] = {
+ { "if", 2, COND_IF },
+ { "elif", 4, COND_ELIF },
+ { "else", 4, COND_ELSE },
+ { "", 0, COND_NONE },
+ };
+ const struct cond_tbl_s *p;
+
+ for (p = cond_tbl; p->len; p++) {
+ if (strncmp(l, p->name, p->len) == 0 &&
+ isspace((unsigned char)l[p->len])) {
+ if (t)
+ *t = l + p->len;
+ break;
+ }
+ }
+ return p->cond;
+}
+
+private int
+check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
+{
+ int last_cond;
+ last_cond = ms->c.li[cont_level].last_cond;
+
+ switch (cond) {
+ case COND_IF:
+ if (last_cond != COND_NONE && last_cond != COND_ELIF) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "syntax error: `if'");
+ return -1;
+ }
+ last_cond = COND_IF;
+ break;
+
+ case COND_ELIF:
+ if (last_cond != COND_IF && last_cond != COND_ELIF) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "syntax error: `elif'");
+ return -1;
+ }
+ last_cond = COND_ELIF;
+ break;
+
+ case COND_ELSE:
+ if (last_cond != COND_IF && last_cond != COND_ELIF) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "syntax error: `else'");
+ return -1;
+ }
+ last_cond = COND_NONE;
+ break;
+
+ case COND_NONE:
+ last_cond = COND_NONE;
+ break;
+ }
+
+ ms->c.li[cont_level].last_cond = last_cond;
+ return 0;
+}
+#endif /* ENABLE_CONDITIONALS */
+
+private int
+parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp)
+{
+ const char *l = *lp;
+
+ while (!isspace((unsigned char)*++l))
+ switch (*l) {
+ case CHAR_INDIRECT_RELATIVE:
+ m->str_flags |= INDIRECT_RELATIVE;
+ break;
+ default:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "indirect modifier `%c' "
+ "invalid", *l);
+ *lp = l;
+ return -1;
+ }
+ *lp = l;
+ return 0;
+}
+
+private void
+parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp,
+ int op)
+{
+ const char *l = *lp;
+ char *t;
+ uint64_t val;
+
+ ++l;
+ m->mask_op |= op;
+ val = (uint64_t)strtoull(l, &t, 0);
+ l = t;
+ m->num_mask = file_signextend(ms, m, val);
+ eatsize(&l);
+ *lp = l;
+}
+
+private int
+parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp)
+{
+ const char *l = *lp;
+ char *t;
+ int have_range = 0;
+
+ while (!isspace((unsigned char)*++l)) {
+ switch (*l) {
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8':
+ case '9':
+ if (have_range && (ms->flags & MAGIC_CHECK))
+ file_magwarn(ms, "multiple ranges");
+ have_range = 1;
+ m->str_range = CAST(uint32_t, strtoul(l, &t, 0));
+ if (m->str_range == 0)
+ file_magwarn(ms, "zero range");
+ l = t - 1;
+ break;
+ case CHAR_COMPACT_WHITESPACE:
+ m->str_flags |= STRING_COMPACT_WHITESPACE;
+ break;
+ case CHAR_COMPACT_OPTIONAL_WHITESPACE:
+ m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE;
+ break;
+ case CHAR_IGNORE_LOWERCASE:
+ m->str_flags |= STRING_IGNORE_LOWERCASE;
+ break;
+ case CHAR_IGNORE_UPPERCASE:
+ m->str_flags |= STRING_IGNORE_UPPERCASE;
+ break;
+ case CHAR_REGEX_OFFSET_START:
+ m->str_flags |= REGEX_OFFSET_START;
+ break;
+ case CHAR_BINTEST:
+ m->str_flags |= STRING_BINTEST;
+ break;
+ case CHAR_TEXTTEST:
+ m->str_flags |= STRING_TEXTTEST;
+ break;
+ case CHAR_TRIM:
+ m->str_flags |= STRING_TRIM;
+ break;
+ case CHAR_PSTRING_1_LE:
+#define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a)
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_1_LE);
+ break;
+ case CHAR_PSTRING_2_BE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_2_BE);
+ break;
+ case CHAR_PSTRING_2_LE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_2_LE);
+ break;
+ case CHAR_PSTRING_4_BE:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ SET_LENGTH(PSTRING_4_BE);
+ break;
+ case CHAR_PSTRING_4_LE:
+ switch (m->type) {
+ case FILE_PSTRING:
+ case FILE_REGEX:
+ break;
+ default:
+ goto bad;
+ }
+ SET_LENGTH(PSTRING_4_LE);
+ break;
+ case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
+ if (m->type != FILE_PSTRING)
+ goto bad;
+ m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
+ break;
+ default:
+ bad:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "string modifier `%c' "
+ "invalid", *l);
+ goto out;
+ }
+ /* allow multiple '/' for readability */
+ if (l[1] == '/' && !isspace((unsigned char)l[2]))
+ l++;
+ }
+ if (string_modifier_check(ms, m) == -1)
+ goto out;
+ *lp = l;
+ return 0;
+out:
+ *lp = l;
+ return -1;
+}
+
+/*
+ * parse one line from magic file, put into magic[index++] if valid
+ */
+private int
+parse(struct magic_set *ms, struct magic_entry *me, const char *line,
+ size_t lineno, int action)
+{
+#ifdef ENABLE_CONDITIONALS
+ static uint32_t last_cont_level = 0;
+#endif
+ size_t i;
+ struct magic *m;
+ const char *l = line;
+ char *t;
+ int op;
+ uint32_t cont_level;
+ int32_t diff;
+
+ cont_level = 0;
+
+ /*
+ * Parse the offset.
+ */
+ while (*l == '>') {
+ ++l; /* step over */
+ cont_level++;
+ }
+#ifdef ENABLE_CONDITIONALS
+ if (cont_level == 0 || cont_level > last_cont_level)
+ if (file_check_mem(ms, cont_level) == -1)
+ return -1;
+ last_cont_level = cont_level;
+#endif
+ if (cont_level != 0) {
+ if (me->mp == NULL) {
+ file_magerror(ms, "No current entry for continuation");
+ return -1;
+ }
+ if (me->cont_count == 0) {
+ file_magerror(ms, "Continuations present with 0 count");
+ return -1;
+ }
+ m = &me->mp[me->cont_count - 1];
+ diff = (int32_t)cont_level - (int32_t)m->cont_level;
+ if (diff > 1)
+ file_magwarn(ms, "New continuation level %u is more "
+ "than one larger than current level %u", cont_level,
+ m->cont_level);
+ if (me->cont_count == me->max_count) {
+ struct magic *nm;
+ size_t cnt = me->max_count + ALLOC_CHUNK;
+ if ((nm = CAST(struct magic *, realloc(me->mp,
+ sizeof(*nm) * cnt))) == NULL) {
+ file_oomem(ms, sizeof(*nm) * cnt);
+ return -1;
+ }
+ me->mp = m = nm;
+ me->max_count = CAST(uint32_t, cnt);
+ }
+ m = &me->mp[me->cont_count++];
+ (void)memset(m, 0, sizeof(*m));
+ m->cont_level = cont_level;
+ } else {
+ static const size_t len = sizeof(*m) * ALLOC_CHUNK;
+ if (me->mp != NULL)
+ return 1;
+ if ((m = CAST(struct magic *, malloc(len))) == NULL) {
+ file_oomem(ms, len);
+ return -1;
+ }
+ me->mp = m;
+ me->max_count = ALLOC_CHUNK;
+ (void)memset(m, 0, sizeof(*m));
+ m->factor_op = FILE_FACTOR_OP_NONE;
+ m->cont_level = 0;
+ me->cont_count = 1;
+ }
+ m->lineno = CAST(uint32_t, lineno);
+
+ if (*l == '&') { /* m->cont_level == 0 checked below. */
+ ++l; /* step over */
+ m->flag |= OFFADD;
+ }
+ if (*l == '(') {
+ ++l; /* step over */
+ m->flag |= INDIR;
+ if (m->flag & OFFADD)
+ m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
+
+ if (*l == '&') { /* m->cont_level == 0 checked below */
+ ++l; /* step over */
+ m->flag |= OFFADD;
+ }
+ }
+ /* Indirect offsets are not valid at level 0. */
+ if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "relative offset at level 0");
+ return -1;
+ }
+
+ /* get offset, then skip over it */
+ m->offset = (uint32_t)strtoul(l, &t, 0);
+ if (l == t) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "offset `%s' invalid", l);
+ return -1;
+ }
+ l = t;
+
+ if (m->flag & INDIR) {
+ m->in_type = FILE_LONG;
+ m->in_offset = 0;
+ m->in_op = 0;
+ /*
+ * read [.,lbs][+-]nnnnn)
+ */
+ if (*l == '.' || *l == ',') {
+ if (*l == ',')
+ m->in_op |= FILE_OPSIGNED;
+ l++;
+ switch (*l) {
+ case 'l':
+ m->in_type = FILE_LELONG;
+ break;
+ case 'L':
+ m->in_type = FILE_BELONG;
+ break;
+ case 'm':
+ m->in_type = FILE_MELONG;
+ break;
+ case 'h':
+ case 's':
+ m->in_type = FILE_LESHORT;
+ break;
+ case 'H':
+ case 'S':
+ m->in_type = FILE_BESHORT;
+ break;
+ case 'c':
+ case 'b':
+ case 'C':
+ case 'B':
+ m->in_type = FILE_BYTE;
+ break;
+ case 'e':
+ case 'f':
+ case 'g':
+ m->in_type = FILE_LEDOUBLE;
+ break;
+ case 'E':
+ case 'F':
+ case 'G':
+ m->in_type = FILE_BEDOUBLE;
+ break;
+ case 'i':
+ m->in_type = FILE_LEID3;
+ break;
+ case 'I':
+ m->in_type = FILE_BEID3;
+ break;
+ default:
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "indirect offset type `%c' invalid",
+ *l);
+ return -1;
+ }
+ l++;
+ }
+
+ if (*l == '~') {
+ m->in_op |= FILE_OPINVERSE;
+ l++;
+ }
+ if ((op = get_op(*l)) != -1) {
+ m->in_op |= op;
+ l++;
+ }
+ if (*l == '(') {
+ m->in_op |= FILE_OPINDIRECT;
+ l++;
+ }
+ if (isdigit((unsigned char)*l) || *l == '-') {
+ m->in_offset = (int32_t)strtol(l, &t, 0);
+ if (l == t) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "in_offset `%s' invalid", l);
+ return -1;
+ }
+ l = t;
+ }
+ if (*l++ != ')' ||
+ ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "missing ')' in indirect offset");
+ return -1;
+ }
+ }
+ EATAB;
+
+#ifdef ENABLE_CONDITIONALS
+ m->cond = get_cond(l, &l);
+ if (check_cond(ms, m->cond, cont_level) == -1)
+ return -1;
+
+ EATAB;
+#endif
+
+ /*
+ * Parse the type.
+ */
+ if (*l == 'u') {
+ /*
+ * Try it as a keyword type prefixed by "u"; match what
+ * follows the "u". If that fails, try it as an SUS
+ * integer type.
+ */
+ m->type = get_type(type_tbl, l + 1, &l);
+ if (m->type == FILE_INVALID) {
+ /*
+ * Not a keyword type; parse it as an SUS type,
+ * 'u' possibly followed by a number or C/S/L.
+ */
+ m->type = get_standard_integer_type(l, &l);
+ }
+ /* It's unsigned. */
+ if (m->type != FILE_INVALID)
+ m->flag |= UNSIGNED;
+ } else {
+ /*
+ * Try it as a keyword type. If that fails, try it as
+ * an SUS integer type if it begins with "d" or as an
+ * SUS string type if it begins with "s". In any case,
+ * it's not unsigned.
+ */
+ m->type = get_type(type_tbl, l, &l);
+ if (m->type == FILE_INVALID) {
+ /*
+ * Not a keyword type; parse it as an SUS type,
+ * either 'd' possibly followed by a number or
+ * C/S/L, or just 's'.
+ */
+ if (*l == 'd')
+ m->type = get_standard_integer_type(l, &l);
+ else if (*l == 's' && !isalpha((unsigned char)l[1])) {
+ m->type = FILE_STRING;
+ ++l;
+ }
+ }
+ }
+
+ if (m->type == FILE_INVALID) {
+ /* Not found - try it as a special keyword. */
+ m->type = get_type(special_tbl, l, &l);
+ }
+
+ if (m->type == FILE_INVALID) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "type `%s' invalid", l);
+ return -1;
+ }
+
+ /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
+ /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
+
+ m->mask_op = 0;
+ if (*l == '~') {
+ if (!IS_STRING(m->type))
+ m->mask_op |= FILE_OPINVERSE;
+ else if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "'~' invalid for string types");
+ ++l;
+ }
+ m->str_range = 0;
+ m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0;
+ if ((op = get_op(*l)) != -1) {
+ if (IS_STRING(m->type)) {
+ int r;
+
+ if (op != FILE_OPDIVIDE) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms,
+ "invalid string/indirect op: "
+ "`%c'", *t);
+ return -1;
+ }
+
+ if (m->type == FILE_INDIRECT)
+ r = parse_indirect_modifier(ms, m, &l);
+ else
+ r = parse_string_modifier(ms, m, &l);
+ if (r == -1)
+ return -1;
+ } else
+ parse_op_modifier(ms, m, &l, op);
+ }
+
+ /*
+ * We used to set mask to all 1's here, instead let's just not do
+ * anything if mask = 0 (unless you have a better idea)
+ */
+ EATAB;
+
+ switch (*l) {
+ case '>':
+ case '<':
+ m->reln = *l;
+ ++l;
+ if (*l == '=') {
+ if (ms->flags & MAGIC_CHECK) {
+ file_magwarn(ms, "%c= not supported",
+ m->reln);
+ return -1;
+ }
+ ++l;
+ }
+ break;
+ /* Old-style anding: "0 byte &0x80 dynamically linked" */
+ case '&':
+ case '^':
+ case '=':
+ m->reln = *l;
+ ++l;
+ if (*l == '=') {
+ /* HP compat: ignore &= etc. */
+ ++l;
+ }
+ break;
+ case '!':
+ m->reln = *l;
+ ++l;
+ break;
+ default:
+ m->reln = '='; /* the default relation */
+ if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
+ isspace((unsigned char)l[1])) || !l[1])) {
+ m->reln = *l;
+ ++l;
+ }
+ break;
+ }
+ /*
+ * Grab the value part, except for an 'x' reln.
+ */
+ if (m->reln != 'x' && getvalue(ms, m, &l, action))
+ return -1;
+
+ /*
+ * TODO finish this macro and start using it!
+ * #define offsetcheck {if (offset > ms->bytes_max -1)
+ * magwarn("offset too big"); }
+ */
+
+ /*
+ * Now get last part - the description
+ */
+ EATAB;
+ if (l[0] == '\b') {
+ ++l;
+ m->flag |= NOSPACE;
+ } else if ((l[0] == '\\') && (l[1] == 'b')) {
+ ++l;
+ ++l;
+ m->flag |= NOSPACE;
+ }
+ for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
+ continue;
+ if (i == sizeof(m->desc)) {
+ m->desc[sizeof(m->desc) - 1] = '\0';
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "description `%s' truncated", m->desc);
+ }
+
+ /*
+ * We only do this check while compiling, or if any of the magic
+ * files were not compiled.
+ */
+ if (ms->flags & MAGIC_CHECK) {
+ if (check_format(ms, m) == -1)
+ return -1;
+ }
+#ifndef COMPILE_ONLY
+ if (action == FILE_CHECK) {
+ file_mdump(m);
+ }
+#endif
+ m->mimetype[0] = '\0'; /* initialise MIME type to none */
+ return 0;
+}
+
+/*
+ * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
+ * if valid
+ */
+private int
+parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
+{
+ const char *l = line;
+ char *el;
+ unsigned long factor;
+ struct magic *m = &me->mp[0];
+
+ if (m->factor_op != FILE_FACTOR_OP_NONE) {
+ file_magwarn(ms,
+ "Current entry already has a strength type: %c %d",
+ m->factor_op, m->factor);
+ return -1;
+ }
+ if (m->type == FILE_NAME) {
+ file_magwarn(ms, "%s: Strength setting is not supported in "
+ "\"name\" magic entries", m->value.s);
+ return -1;
+ }
+ EATAB;
+ switch (*l) {
+ case FILE_FACTOR_OP_NONE:
+ case FILE_FACTOR_OP_PLUS:
+ case FILE_FACTOR_OP_MINUS:
+ case FILE_FACTOR_OP_TIMES:
+ case FILE_FACTOR_OP_DIV:
+ m->factor_op = *l++;
+ break;
+ default:
+ file_magwarn(ms, "Unknown factor op `%c'", *l);
+ return -1;
+ }
+ EATAB;
+ factor = strtoul(l, &el, 0);
+ if (factor > 255) {
+ file_magwarn(ms, "Too large factor `%lu'", factor);
+ goto out;
+ }
+ if (*el && !isspace((unsigned char)*el)) {
+ file_magwarn(ms, "Bad factor `%s'", l);
+ goto out;
+ }
+ m->factor = (uint8_t)factor;
+ if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
+ file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
+ m->factor_op, m->factor);
+ goto out;
+ }
+ return 0;
+out:
+ m->factor_op = FILE_FACTOR_OP_NONE;
+ m->factor = 0;
+ return -1;
+}
+
+private int
+goodchar(unsigned char x, const char *extra)
+{
+ return (isascii(x) && isalnum(x)) || strchr(extra, x);
+}
+
+private int
+parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line,
+ off_t off, size_t len, const char *name, const char *extra, int nt)
+{
+ size_t i;
+ const char *l = line;
+ struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
+ char *buf = CAST(char *, CAST(void *, m)) + off;
+
+ if (buf[0] != '\0') {
+ len = nt ? strlen(buf) : len;
+ file_magwarn(ms, "Current entry already has a %s type "
+ "`%.*s', new type `%s'", name, (int)len, buf, l);
+ return -1;
+ }
+
+ if (*m->desc == '\0') {
+ file_magwarn(ms, "Current entry does not yet have a "
+ "description for adding a %s type", name);
+ return -1;
+ }
+
+ EATAB;
+ for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++)
+ continue;
+
+ if (i == len && *l) {
+ if (nt)
+ buf[len - 1] = '\0';
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "%s type `%s' truncated %"
+ SIZE_T_FORMAT "u", name, line, i);
+ } else {
+ if (!isspace((unsigned char)*l) && !goodchar(*l, extra))
+ file_magwarn(ms, "%s type `%s' has bad char '%c'",
+ name, line, *l);
+ if (nt)
+ buf[i] = '\0';
+ }
+
+ if (i > 0)
+ return 0;
+
+ file_magerror(ms, "Bad magic entry '%s'", line);
+ return -1;
+}
+
+/*
+ * Parse an Apple CREATOR/TYPE annotation from magic file and put it into
+ * magic[index - 1]
+ */
+private int
+parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
+{
+ struct magic *m = &me->mp[0];
+
+ return parse_extra(ms, me, line,
+ CAST(off_t, offsetof(struct magic, apple)),
+ sizeof(m->apple), "APPLE", "!+-./?", 0);
+}
+
+/*
+ * Parse a comma-separated list of extensions
+ */
+private int
+parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line)
+{
+ struct magic *m = &me->mp[0];
+
+ return parse_extra(ms, me, line,
+ CAST(off_t, offsetof(struct magic, ext)),
+ sizeof(m->ext), "EXTENSION", ",!+-/@", 0);
+}
+
+/*
+ * parse a MIME annotation line from magic file, put into magic[index - 1]
+ * if valid
+ */
+private int
+parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
+{
+ struct magic *m = &me->mp[0];
+
+ return parse_extra(ms, me, line,
+ CAST(off_t, offsetof(struct magic, mimetype)),
+ sizeof(m->mimetype), "MIME", "+-/.", 1);
+}
+
+private int
+check_format_type(const char *ptr, int type, const char **estr)
+{
+ int quad = 0, h;
+ size_t len, cnt;
+ if (*ptr == '\0') {
+ /* Missing format string; bad */
+ *estr = "missing format spec";
+ return -1;
+ }
+
+ switch (file_formats[type]) {
+ case FILE_FMT_QUAD:
+ quad = 1;
+ /*FALLTHROUGH*/
+ case FILE_FMT_NUM:
+ if (quad == 0) {
+ switch (type) {
+ case FILE_BYTE:
+ h = 2;
+ break;
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ h = 1;
+ break;
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_LEID3:
+ case FILE_BEID3:
+ case FILE_INDIRECT:
+ h = 0;
+ break;
+ default:
+ abort();
+ }
+ } else
+ h = 0;
+ if (*ptr == '-')
+ ptr++;
+ if (*ptr == '.')
+ ptr++;
+ if (*ptr == '#')
+ ptr++;
+#define CHECKLEN() do { \
+ for (len = cnt = 0; isdigit((unsigned char)*ptr); ptr++, cnt++) \
+ len = len * 10 + (*ptr - '0'); \
+ if (cnt > 5 || len > 1024) \
+ goto toolong; \
+} while (/*CONSTCOND*/0)
+
+ CHECKLEN();
+ if (*ptr == '.')
+ ptr++;
+ CHECKLEN();
+ if (quad) {
+ if (*ptr++ != 'l')
+ goto invalid;
+ if (*ptr++ != 'l')
+ goto invalid;
+ }
+
+ switch (*ptr++) {
+#ifdef STRICT_FORMAT /* "long" formats are int formats for us */
+ /* so don't accept the 'l' modifier */
+ case 'l':
+ switch (*ptr++) {
+ case 'i':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (h == 0)
+ return 0;
+ /*FALLTHROUGH*/
+ default:
+ goto invalid;
+ }
+
+ /*
+ * Don't accept h and hh modifiers. They make writing
+ * magic entries more complicated, for very little benefit
+ */
+ case 'h':
+ if (h-- <= 0)
+ goto invalid;
+ switch (*ptr++) {
+ case 'h':
+ if (h-- <= 0)
+ goto invalid;
+ switch (*ptr++) {
+ case 'i':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ return 0;
+ default:
+ goto invalid;
+ }
+ case 'i':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (h == 0)
+ return 0;
+ /*FALLTHROUGH*/
+ default:
+ goto invalid;
+ }
+#endif
+ case 'c':
+ if (h == 2)
+ return 0;
+ goto invalid;
+ case 'i':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+#ifdef STRICT_FORMAT
+ if (h == 0)
+ return 0;
+ /*FALLTHROUGH*/
+#else
+ return 0;
+#endif
+ default:
+ goto invalid;
+ }
+
+ case FILE_FMT_FLOAT:
+ case FILE_FMT_DOUBLE:
+ if (*ptr == '-')
+ ptr++;
+ if (*ptr == '.')
+ ptr++;
+ CHECKLEN();
+ if (*ptr == '.')
+ ptr++;
+ CHECKLEN();
+ switch (*ptr++) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ return 0;
+
+ default:
+ goto invalid;
+ }
+
+
+ case FILE_FMT_STR:
+ if (*ptr == '-')
+ ptr++;
+ while (isdigit((unsigned char )*ptr))
+ ptr++;
+ if (*ptr == '.') {
+ ptr++;
+ while (isdigit((unsigned char )*ptr))
+ ptr++;
+ }
+
+ switch (*ptr++) {
+ case 's':
+ return 0;
+ default:
+ goto invalid;
+ }
+
+ default:
+ /* internal error */
+ abort();
+ }
+invalid:
+ *estr = "not valid";
+toolong:
+ *estr = "too long";
+ return -1;
+}
+
+/*
+ * Check that the optional printf format in description matches
+ * the type of the magic.
+ */
+private int
+check_format(struct magic_set *ms, struct magic *m)
+{
+ char *ptr;
+ const char *estr;
+
+ for (ptr = m->desc; *ptr; ptr++)
+ if (*ptr == '%')
+ break;
+ if (*ptr == '\0') {
+ /* No format string; ok */
+ return 1;
+ }
+
+ assert(file_nformats == file_nnames);
+
+ if (m->type >= file_nformats) {
+ file_magwarn(ms, "Internal error inconsistency between "
+ "m->type and format strings");
+ return -1;
+ }
+ if (file_formats[m->type] == FILE_FMT_NONE) {
+ file_magwarn(ms, "No format string for `%s' with description "
+ "`%s'", m->desc, file_names[m->type]);
+ return -1;
+ }
+
+ ptr++;
+ if (check_format_type(ptr, m->type, &estr) == -1) {
+ /*
+ * TODO: this error message is unhelpful if the format
+ * string is not one character long
+ */
+ file_magwarn(ms, "Printf format is %s for type "
+ "`%s' in description `%s'", estr,
+ file_names[m->type], m->desc);
+ return -1;
+ }
+
+ for (; *ptr; ptr++) {
+ if (*ptr == '%') {
+ file_magwarn(ms,
+ "Too many format strings (should have at most one) "
+ "for `%s' with description `%s'",
+ file_names[m->type], m->desc);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Read a numeric value from a pointer, into the value union of a magic
+ * pointer, according to the magic type. Update the string pointer to point
+ * just after the number read. Return 0 for success, non-zero for failure.
+ */
+private int
+getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
+{
+ switch (m->type) {
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_REGEX:
+ case FILE_SEARCH:
+ case FILE_NAME:
+ case FILE_USE:
+ case FILE_DER:
+ *p = getstr(ms, m, *p, action == FILE_COMPILE);
+ if (*p == NULL) {
+ if (ms->flags & MAGIC_CHECK)
+ file_magwarn(ms, "cannot get string from `%s'",
+ m->value.s);
+ return -1;
+ }
+ if (m->type == FILE_REGEX) {
+ file_regex_t rx;
+ int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED);
+ if (rc) {
+ if (ms->flags & MAGIC_CHECK)
+ file_regerror(&rx, rc, ms);
+ }
+ file_regfree(&rx);
+ return rc ? -1 : 0;
+ }
+ return 0;
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ if (m->reln != 'x') {
+ char *ep;
+ errno = 0;
+#ifdef HAVE_STRTOF
+ m->value.f = strtof(*p, &ep);
+#else
+ m->value.f = (float)strtod(*p, &ep);
+#endif
+ if (errno == 0)
+ *p = ep;
+ }
+ return 0;
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ if (m->reln != 'x') {
+ char *ep;
+ errno = 0;
+ m->value.d = strtod(*p, &ep);
+ if (errno == 0)
+ *p = ep;
+ }
+ return 0;
+ default:
+ if (m->reln != 'x') {
+ char *ep;
+ uint64_t ull;
+ errno = 0;
+ ull = (uint64_t)strtoull(*p, &ep, 0);
+ m->value.q = file_signextend(ms, m, ull);
+ if (*p == ep) {
+ file_magwarn(ms, "Unparseable number `%s'", *p);
+ } else {
+ size_t ts = typesize(m->type);
+ uint64_t x;
+ const char *q;
+
+ if (ts == (size_t)~0) {
+ file_magwarn(ms, "Expected numeric type got `%s'",
+ type_tbl[m->type].name);
+ }
+ for (q = *p; isspace((unsigned char)*q); q++)
+ continue;
+ if (*q == '-')
+ ull = -(int64_t)ull;
+ switch (ts) {
+ case 1:
+ x = ull & ~0xffULL;
+ break;
+ case 2:
+ x = ull & ~0xffffULL;
+ break;
+ case 4:
+ x = ull & ~0xffffffffULL;
+ break;
+ case 8:
+ x = 0;
+ break;
+ default:
+ abort();
+ }
+ if (x) {
+ file_magwarn(ms, "Overflow for numeric type `%s' value %#" PRIx64,
+ type_tbl[m->type].name, ull);
+ }
+ }
+ if (errno == 0) {
+ *p = ep;
+ eatsize(p);
+ }
+ }
+ return 0;
+ }
+}
+
+/*
+ * Convert a string containing C character escapes. Stop at an unescaped
+ * space or tab.
+ * Copy the converted version to "m->value.s", and the length in m->vallen.
+ * Return updated scan pointer as function result. Warn if set.
+ */
+private const char *
+getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
+{
+ const char *origs = s;
+ char *p = m->value.s;
+ size_t plen = sizeof(m->value.s);
+ char *origp = p;
+ char *pmax = p + plen - 1;
+ int c;
+ int val;
+
+ while ((c = *s++) != '\0') {
+ if (isspace((unsigned char) c))
+ break;
+ if (p >= pmax) {
+ file_error(ms, 0, "string too long: `%s'", origs);
+ return NULL;
+ }
+ if (c == '\\') {
+ switch(c = *s++) {
+
+ case '\0':
+ if (warn)
+ file_magwarn(ms, "incomplete escape");
+ s--;
+ goto out;
+
+ case '\t':
+ if (warn) {
+ file_magwarn(ms,
+ "escaped tab found, use \\t instead");
+ warn = 0; /* already did */
+ }
+ /*FALLTHROUGH*/
+ default:
+ if (warn) {
+ if (isprint((unsigned char)c)) {
+ /* Allow escaping of
+ * ``relations'' */
+ if (strchr("<>&^=!", c) == NULL
+ && (m->type != FILE_REGEX ||
+ strchr("[]().*?^$|{}", c)
+ == NULL)) {
+ file_magwarn(ms, "no "
+ "need to escape "
+ "`%c'", c);
+ }
+ } else {
+ file_magwarn(ms,
+ "unknown escape sequence: "
+ "\\%03o", c);
+ }
+ }
+ /*FALLTHROUGH*/
+ /* space, perhaps force people to use \040? */
+ case ' ':
+#if 0
+ /*
+ * Other things people escape, but shouldn't need to,
+ * so we disallow them
+ */
+ case '\'':
+ case '"':
+ case '?':
+#endif
+ /* Relations */
+ case '>':
+ case '<':
+ case '&':
+ case '^':
+ case '=':
+ case '!':
+ /* and baskslash itself */
+ case '\\':
+ *p++ = (char) c;
+ break;
+
+ case 'a':
+ *p++ = '\a';
+ break;
+
+ case 'b':
+ *p++ = '\b';
+ break;
+
+ case 'f':
+ *p++ = '\f';
+ break;
+
+ case 'n':
+ *p++ = '\n';
+ break;
+
+ case 'r':
+ *p++ = '\r';
+ break;
+
+ case 't':
+ *p++ = '\t';
+ break;
+
+ case 'v':
+ *p++ = '\v';
+ break;
+
+ /* \ and up to 3 octal digits */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = c - '0';
+ c = *s++; /* try for 2 */
+ if (c >= '0' && c <= '7') {
+ val = (val << 3) | (c - '0');
+ c = *s++; /* try for 3 */
+ if (c >= '0' && c <= '7')
+ val = (val << 3) | (c-'0');
+ else
+ --s;
+ }
+ else
+ --s;
+ *p++ = (char)val;
+ break;
+
+ /* \x and up to 2 hex digits */
+ case 'x':
+ val = 'x'; /* Default if no digits */
+ c = hextoint(*s++); /* Get next char */
+ if (c >= 0) {
+ val = c;
+ c = hextoint(*s++);
+ if (c >= 0)
+ val = (val << 4) + c;
+ else
+ --s;
+ } else
+ --s;
+ *p++ = (char)val;
+ break;
+ }
+ } else
+ *p++ = (char)c;
+ }
+ --s;
+out:
+ *p = '\0';
+ m->vallen = CAST(unsigned char, (p - origp));
+ if (m->type == FILE_PSTRING)
+ m->vallen += (unsigned char)file_pstring_length_size(m);
+ return s;
+}
+
+
+/* Single hex char to int; -1 if not a hex char. */
+private int
+hextoint(int c)
+{
+ if (!isascii((unsigned char) c))
+ return -1;
+ if (isdigit((unsigned char) c))
+ return c - '0';
+ if ((c >= 'a') && (c <= 'f'))
+ return c + 10 - 'a';
+ if (( c>= 'A') && (c <= 'F'))
+ return c + 10 - 'A';
+ return -1;
+}
+
+
+/*
+ * Print a string containing C character escapes.
+ */
+protected void
+file_showstr(FILE *fp, const char *s, size_t len)
+{
+ char c;
+
+ for (;;) {
+ if (len == ~0U) {
+ c = *s++;
+ if (c == '\0')
+ break;
+ }
+ else {
+ if (len-- == 0)
+ break;
+ c = *s++;
+ }
+ if (c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
+ (void) fputc(c, fp);
+ else {
+ (void) fputc('\\', fp);
+ switch (c) {
+ case '\a':
+ (void) fputc('a', fp);
+ break;
+
+ case '\b':
+ (void) fputc('b', fp);
+ break;
+
+ case '\f':
+ (void) fputc('f', fp);
+ break;
+
+ case '\n':
+ (void) fputc('n', fp);
+ break;
+
+ case '\r':
+ (void) fputc('r', fp);
+ break;
+
+ case '\t':
+ (void) fputc('t', fp);
+ break;
+
+ case '\v':
+ (void) fputc('v', fp);
+ break;
+
+ default:
+ (void) fprintf(fp, "%.3o", c & 0377);
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * eatsize(): Eat the size spec from a number [eg. 10UL]
+ */
+private void
+eatsize(const char **p)
+{
+ const char *l = *p;
+
+ if (LOWCASE(*l) == 'u')
+ l++;
+
+ switch (LOWCASE(*l)) {
+ case 'l': /* long */
+ case 's': /* short */
+ case 'h': /* short */
+ case 'b': /* char/byte */
+ case 'c': /* char/byte */
+ l++;
+ /*FALLTHROUGH*/
+ default:
+ break;
+ }
+
+ *p = l;
+}
+
+/*
+ * handle a buffer containing a compiled file.
+ */
+private struct magic_map *
+apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len)
+{
+ struct magic_map *map;
+
+ if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
+ file_oomem(ms, sizeof(*map));
+ return NULL;
+ }
+ map->len = len;
+ map->p = buf;
+ map->type = MAP_TYPE_USER;
+ if (check_buffer(ms, map, "buffer") != 0) {
+ apprentice_unmap(map);
+ return NULL;
+ }
+ return map;
+}
+
+/*
+ * handle a compiled file.
+ */
+
+private struct magic_map *
+apprentice_map(struct magic_set *ms, const char *fn)
+{
+ int fd;
+ struct stat st;
+ char *dbname = NULL;
+ struct magic_map *map;
+ struct magic_map *rv = NULL;
+
+ fd = -1;
+ if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
+ file_oomem(ms, sizeof(*map));
+ goto error;
+ }
+ map->type = MAP_TYPE_USER; /* unspecified */
+
+ dbname = mkdbname(ms, fn, 0);
+ if (dbname == NULL)
+ goto error;
+
+ if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
+ goto error;
+
+ if (fstat(fd, &st) == -1) {
+ file_error(ms, errno, "cannot stat `%s'", dbname);
+ goto error;
+ }
+ if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) {
+ file_error(ms, 0, "file `%s' is too %s", dbname,
+ st.st_size < 8 ? "small" : "large");
+ goto error;
+ }
+
+ map->len = (size_t)st.st_size;
+#ifdef QUICK
+ map->type = MAP_TYPE_MMAP;
+ if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
+ file_error(ms, errno, "cannot map `%s'", dbname);
+ goto error;
+ }
+#else
+ map->type = MAP_TYPE_MALLOC;
+ if ((map->p = CAST(void *, malloc(map->len))) == NULL) {
+ file_oomem(ms, map->len);
+ goto error;
+ }
+ if (read(fd, map->p, map->len) != (ssize_t)map->len) {
+ file_badread(ms);
+ goto error;
+ }
+#define RET 1
+#endif
+ (void)close(fd);
+ fd = -1;
+
+ if (check_buffer(ms, map, dbname) != 0) {
+ rv = (struct magic_map *)-1;
+ goto error;
+ }
+#ifdef QUICK
+ if (mprotect(map->p, (size_t)st.st_size, PROT_READ) == -1) {
+ file_error(ms, errno, "cannot mprotect `%s'", dbname);
+ goto error;
+ }
+#endif
+
+ free(dbname);
+ return map;
+
+error:
+ if (fd != -1)
+ (void)close(fd);
+ apprentice_unmap(map);
+ free(dbname);
+ return rv;
+}
+
+private int
+check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname)
+{
+ uint32_t *ptr;
+ uint32_t entries, nentries;
+ uint32_t version;
+ int i, needsbyteswap;
+
+ ptr = CAST(uint32_t *, map->p);
+ if (*ptr != MAGICNO) {
+ if (swap4(*ptr) != MAGICNO) {
+ file_error(ms, 0, "bad magic in `%s'", dbname);
+ return -1;
+ }
+ needsbyteswap = 1;
+ } else
+ needsbyteswap = 0;
+ if (needsbyteswap)
+ version = swap4(ptr[1]);
+ else
+ version = ptr[1];
+ if (version != VERSIONNO) {
+ file_error(ms, 0, "File %s supports only version %d magic "
+ "files. `%s' is version %d", VERSION,
+ VERSIONNO, dbname, version);
+ return -1;
+ }
+ entries = (uint32_t)(map->len / sizeof(struct magic));
+ if ((entries * sizeof(struct magic)) != map->len) {
+ file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not "
+ "a multiple of %" SIZE_T_FORMAT "u",
+ dbname, map->len, sizeof(struct magic));
+ return -1;
+ }
+ map->magic[0] = CAST(struct magic *, map->p) + 1;
+ nentries = 0;
+ for (i = 0; i < MAGIC_SETS; i++) {
+ if (needsbyteswap)
+ map->nmagic[i] = swap4(ptr[i + 2]);
+ else
+ map->nmagic[i] = ptr[i + 2];
+ if (i != MAGIC_SETS - 1)
+ map->magic[i + 1] = map->magic[i] + map->nmagic[i];
+ nentries += map->nmagic[i];
+ }
+ if (entries != nentries + 1) {
+ file_error(ms, 0, "Inconsistent entries in `%s' %u != %u",
+ dbname, entries, nentries + 1);
+ return -1;
+ }
+ if (needsbyteswap)
+ for (i = 0; i < MAGIC_SETS; i++)
+ byteswap(map->magic[i], map->nmagic[i]);
+ return 0;
+}
+
+/*
+ * handle an mmaped file.
+ */
+private int
+apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn)
+{
+ static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS;
+ static const size_t m = sizeof(**map->magic);
+ int fd = -1;
+ size_t len;
+ char *dbname;
+ int rv = -1;
+ uint32_t i;
+ union {
+ struct magic m;
+ uint32_t h[2 + MAGIC_SETS];
+ } hdr;
+
+ dbname = mkdbname(ms, fn, 1);
+
+ if (dbname == NULL)
+ goto out;
+
+ if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1)
+ {
+ file_error(ms, errno, "cannot open `%s'", dbname);
+ goto out;
+ }
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.h[0] = MAGICNO;
+ hdr.h[1] = VERSIONNO;
+ memcpy(hdr.h + 2, map->nmagic, nm);
+
+ if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) {
+ file_error(ms, errno, "error writing `%s'", dbname);
+ goto out;
+ }
+
+ for (i = 0; i < MAGIC_SETS; i++) {
+ len = m * map->nmagic[i];
+ if (write(fd, map->magic[i], len) != (ssize_t)len) {
+ file_error(ms, errno, "error writing `%s'", dbname);
+ goto out;
+ }
+ }
+
+ if (fd != -1)
+ (void)close(fd);
+ rv = 0;
+out:
+ apprentice_unmap(map);
+ free(dbname);
+ return rv;
+}
+
+private const char ext[] = ".mgc";
+/*
+ * make a dbname
+ */
+private char *
+mkdbname(struct magic_set *ms, const char *fn, int strip)
+{
+ const char *p, *q;
+ char *buf;
+
+ if (strip) {
+ if ((p = strrchr(fn, '/')) != NULL)
+ fn = ++p;
+ }
+
+ for (q = fn; *q; q++)
+ continue;
+ /* Look for .mgc */
+ for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
+ if (*p != *q)
+ break;
+
+ /* Did not find .mgc, restore q */
+ if (p >= ext)
+ while (*q)
+ q++;
+
+ q++;
+ /* Compatibility with old code that looked in .mime */
+ if (ms->flags & MAGIC_MIME) {
+ if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0)
+ return NULL;
+ if (access(buf, R_OK) != -1) {
+ ms->flags &= MAGIC_MIME_TYPE;
+ return buf;
+ }
+ free(buf);
+ }
+ if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0)
+ return NULL;
+
+ /* Compatibility with old code that looked in .mime */
+ if (strstr(fn, ".mime") != NULL)
+ ms->flags &= MAGIC_MIME_TYPE;
+ return buf;
+}
+
+/*
+ * Byteswap an mmap'ed file if needed
+ */
+private void
+byteswap(struct magic *magic, uint32_t nmagic)
+{
+ uint32_t i;
+ for (i = 0; i < nmagic; i++)
+ bs1(&magic[i]);
+}
+
+/*
+ * swap a short
+ */
+private uint16_t
+swap2(uint16_t sv)
+{
+ uint16_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+ d[0] = s[1];
+ d[1] = s[0];
+ return rv;
+}
+
+/*
+ * swap an int
+ */
+private uint32_t
+swap4(uint32_t sv)
+{
+ uint32_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = s[1];
+ d[3] = s[0];
+ return rv;
+}
+
+/*
+ * swap a quad
+ */
+private uint64_t
+swap8(uint64_t sv)
+{
+ uint64_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+#if 0
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = s[1];
+ d[3] = s[0];
+ d[4] = s[7];
+ d[5] = s[6];
+ d[6] = s[5];
+ d[7] = s[4];
+#else
+ d[0] = s[7];
+ d[1] = s[6];
+ d[2] = s[5];
+ d[3] = s[4];
+ d[4] = s[3];
+ d[5] = s[2];
+ d[6] = s[1];
+ d[7] = s[0];
+#endif
+ return rv;
+}
+
+/*
+ * byteswap a single magic entry
+ */
+private void
+bs1(struct magic *m)
+{
+ m->cont_level = swap2(m->cont_level);
+ m->offset = swap4((uint32_t)m->offset);
+ m->in_offset = swap4((uint32_t)m->in_offset);
+ m->lineno = swap4((uint32_t)m->lineno);
+ if (IS_STRING(m->type)) {
+ m->str_range = swap4(m->str_range);
+ m->str_flags = swap4(m->str_flags);
+ }
+ else {
+ m->value.q = swap8(m->value.q);
+ m->num_mask = swap8(m->num_mask);
+ }
+}
+
+protected size_t
+file_pstring_length_size(const struct magic *m)
+{
+ switch (m->str_flags & PSTRING_LEN) {
+ case PSTRING_1_LE:
+ return 1;
+ case PSTRING_2_LE:
+ case PSTRING_2_BE:
+ return 2;
+ case PSTRING_4_LE:
+ case PSTRING_4_BE:
+ return 4;
+ default:
+ abort(); /* Impossible */
+ return 1;
+ }
+}
+protected size_t
+file_pstring_get_length(const struct magic *m, const char *ss)
+{
+ size_t len = 0;
+ const unsigned char *s = (const unsigned char *)ss;
+ unsigned int s3, s2, s1, s0;
+
+ switch (m->str_flags & PSTRING_LEN) {
+ case PSTRING_1_LE:
+ len = *s;
+ break;
+ case PSTRING_2_LE:
+ s0 = s[0];
+ s1 = s[1];
+ len = (s1 << 8) | s0;
+ break;
+ case PSTRING_2_BE:
+ s0 = s[0];
+ s1 = s[1];
+ len = (s0 << 8) | s1;
+ break;
+ case PSTRING_4_LE:
+ s0 = s[0];
+ s1 = s[1];
+ s2 = s[2];
+ s3 = s[3];
+ len = (s3 << 24) | (s2 << 16) | (s1 << 8) | s0;
+ break;
+ case PSTRING_4_BE:
+ s0 = s[0];
+ s1 = s[1];
+ s2 = s[2];
+ s3 = s[3];
+ len = (s0 << 24) | (s1 << 16) | (s2 << 8) | s3;
+ break;
+ default:
+ abort(); /* Impossible */
+ }
+
+ if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF)
+ len -= file_pstring_length_size(m);
+
+ return len;
+}
+
+protected int
+file_magicfind(struct magic_set *ms, const char *name, struct mlist *v)
+{
+ uint32_t i, j;
+ struct mlist *mlist, *ml;
+
+ mlist = ms->mlist[1];
+
+ for (ml = mlist->next; ml != mlist; ml = ml->next) {
+ struct magic *ma = ml->magic;
+ uint32_t nma = ml->nmagic;
+ for (i = 0; i < nma; i++) {
+ if (ma[i].type != FILE_NAME)
+ continue;
+ if (strcmp(ma[i].value.s, name) == 0) {
+ v->magic = &ma[i];
+ for (j = i + 1; j < nma; j++)
+ if (ma[j].cont_level == 0)
+ break;
+ v->nmagic = j - i;
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/apptype.c b/node_modules/mmmagic/deps/libmagic/src/apptype.c
new file mode 100644
index 0000000..fcd764e
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/apptype.c
@@ -0,0 +1,169 @@
+/*
+ * Adapted from: apptype.c, Written by Eberhard Mattes and put into the
+ * public domain
+ *
+ * Notes: 1. Qualify the filename so that DosQueryAppType does not do extraneous
+ * searches.
+ *
+ * 2. DosQueryAppType will return FAPPTYP_DOS on a file ending with ".com"
+ * (other than an OS/2 exe or Win exe with this name). Eberhard Mattes
+ * remarks Tue, 6 Apr 93: Moreover, it reports the type of the (new and very
+ * bug ridden) Win Emacs as "OS/2 executable".
+ *
+ * 3. apptype() uses the filename if given, otherwise a tmp file is created with
+ * the contents of buf. If buf is not the complete file, apptype can
+ * incorrectly identify the exe type. The "-z" option of "file" is the reason
+ * for this ugly code.
+ */
+
+/*
+ * amai: Darrel Hankerson did the changes described here.
+ *
+ * It remains to check the validity of comments (2.) since it's referred to an
+ * "old" OS/2 version.
+ *
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: apptype.c,v 1.13 2011/09/07 21:57:15 christos Exp $")
+#endif /* lint */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __EMX__
+#include <io.h>
+#define INCL_DOSSESMGR
+#define INCL_DOSERRORS
+#define INCL_DOSFILEMGR
+#include <os2.h>
+typedef ULONG APPTYPE;
+
+protected int
+file_os2_apptype(struct magic_set *ms, const char *fn, const void *buf,
+ size_t nb)
+{
+ APPTYPE rc, type;
+ char path[_MAX_PATH], drive[_MAX_DRIVE], dir[_MAX_DIR],
+ fname[_MAX_FNAME], ext[_MAX_EXT];
+ char *filename;
+ FILE *fp;
+
+ if (fn)
+ filename = strdup(fn);
+ else if ((filename = tempnam("./", "tmp")) == NULL) {
+ file_error(ms, errno, "cannot create tempnam");
+ return -1;
+ }
+ /* qualify the filename to prevent extraneous searches */
+ _splitpath(filename, drive, dir, fname, ext);
+ (void)sprintf(path, "%s%s%s%s", drive,
+ (*dir == '\0') ? "./" : dir,
+ fname,
+ (*ext == '\0') ? "." : ext);
+
+ if (fn == NULL) {
+ if ((fp = fopen(path, "wb")) == NULL) {
+ file_error(ms, errno, "cannot open tmp file `%s'", path);
+ return -1;
+ }
+ if (fwrite(buf, 1, nb, fp) != nb) {
+ file_error(ms, errno, "cannot write tmp file `%s'",
+ path);
+ (void)fclose(fp);
+ return -1;
+ }
+ (void)fclose(fp);
+ }
+ rc = DosQueryAppType((unsigned char *)path, &type);
+
+ if (fn == NULL) {
+ unlink(path);
+ free(filename);
+ }
+#if 0
+ if (rc == ERROR_INVALID_EXE_SIGNATURE)
+ printf("%s: not an executable file\n", fname);
+ else if (rc == ERROR_FILE_NOT_FOUND)
+ printf("%s: not found\n", fname);
+ else if (rc == ERROR_ACCESS_DENIED)
+ printf("%s: access denied\n", fname);
+ else if (rc != 0)
+ printf("%s: error code = %lu\n", fname, rc);
+ else
+#else
+
+ /*
+ * for our purpose here it's sufficient to just ignore the error and
+ * return w/o success (=0)
+ */
+
+ if (rc)
+ return (0);
+
+#endif
+
+ if (type & FAPPTYP_32BIT)
+ if (file_printf(ms, "32-bit ") == -1)
+ return -1;
+ if (type & FAPPTYP_PHYSDRV) {
+ if (file_printf(ms, "physical device driver") == -1)
+ return -1;
+ } else if (type & FAPPTYP_VIRTDRV) {
+ if (file_printf(ms, "virtual device driver") == -1)
+ return -1;
+ } else if (type & FAPPTYP_DLL) {
+ if (type & FAPPTYP_PROTDLL)
+ if (file_printf(ms, "protected ") == -1)
+ return -1;
+ if (file_printf(ms, "DLL") == -1)
+ return -1;
+ } else if (type & (FAPPTYP_WINDOWSREAL | FAPPTYP_WINDOWSPROT)) {
+ if (file_printf(ms, "Windows executable") == -1)
+ return -1;
+ } else if (type & FAPPTYP_DOS) {
+ /*
+ * The API routine is partially broken on filenames ending
+ * ".com".
+ */
+ if (stricmp(ext, ".com") == 0)
+ if (strncmp((const char *)buf, "MZ", 2))
+ return (0);
+ if (file_printf(ms, "DOS executable") == -1)
+ return -1;
+ /* ---------------------------------------- */
+ /* Might learn more from the magic(4) entry */
+ if (file_printf(ms, ", magic(4)-> ") == -1)
+ return -1;
+ return (0);
+ /* ---------------------------------------- */
+ } else if (type & FAPPTYP_BOUND) {
+ if (file_printf(ms, "bound executable") == -1)
+ return -1;
+ } else if ((type & 7) == FAPPTYP_WINDOWAPI) {
+ if (file_printf(ms, "PM executable") == -1)
+ return -1;
+ } else if (file_printf(ms, "OS/2 executable") == -1)
+ return -1;
+
+ switch (type & (FAPPTYP_NOTWINDOWCOMPAT |
+ FAPPTYP_WINDOWCOMPAT |
+ FAPPTYP_WINDOWAPI)) {
+ case FAPPTYP_NOTWINDOWCOMPAT:
+ if (file_printf(ms, " [NOTWINDOWCOMPAT]") == -1)
+ return -1;
+ break;
+ case FAPPTYP_WINDOWCOMPAT:
+ if (file_printf(ms, " [WINDOWCOMPAT]") == -1)
+ return -1;
+ break;
+ case FAPPTYP_WINDOWAPI:
+ if (file_printf(ms, " [WINDOWAPI]") == -1)
+ return -1;
+ break;
+ }
+ return 1;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/ascmagic.c b/node_modules/mmmagic/deps/libmagic/src/ascmagic.c
new file mode 100644
index 0000000..85a973e
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/ascmagic.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * ASCII magic -- try to detect text encoding.
+ *
+ * Extensively modified by Eric Fischer <enf@pobox.com> in July, 2000,
+ * to handle character codes other than ASCII on a unified basis.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: ascmagic.c,v 1.97 2016/06/27 20:56:25 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define MAXLINELEN 300 /* longest sane line length */
+#define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \
+ || (x) == 0x85 || (x) == '\f')
+
+private unsigned char *encode_utf8(unsigned char *, size_t, unichar *, size_t);
+private size_t trim_nuls(const unsigned char *, size_t);
+
+/*
+ * Undo the NUL-termination kindly provided by process()
+ * but leave at least one byte to look at
+ */
+private size_t
+trim_nuls(const unsigned char *buf, size_t nbytes)
+{
+ while (nbytes > 1 && buf[nbytes - 1] == '\0')
+ nbytes--;
+
+ return nbytes;
+}
+
+protected int
+file_ascmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
+ int text)
+{
+ unichar *ubuf = NULL;
+ size_t ulen = 0;
+ int rv = 1;
+
+ const char *code = NULL;
+ const char *code_mime = NULL;
+ const char *type = NULL;
+
+ nbytes = trim_nuls(buf, nbytes);
+
+ /* If file doesn't look like any sort of text, give up. */
+ if (file_encoding(ms, buf, nbytes, &ubuf, &ulen, &code, &code_mime,
+ &type) == 0)
+ rv = 0;
+ else
+ rv = file_ascmagic_with_encoding(ms, buf, nbytes, ubuf, ulen, code,
+ type, text);
+
+ free(ubuf);
+
+ return rv;
+}
+
+protected int
+file_ascmagic_with_encoding(struct magic_set *ms, const unsigned char *buf,
+ size_t nbytes, unichar *ubuf, size_t ulen, const char *code,
+ const char *type, int text)
+{
+ unsigned char *utf8_buf = NULL, *utf8_end;
+ size_t mlen, i;
+ int rv = -1;
+ int mime = ms->flags & MAGIC_MIME;
+
+ const char *subtype = NULL;
+ const char *subtype_mime = NULL;
+
+ int has_escapes = 0;
+ int has_backspace = 0;
+ int seen_cr = 0;
+
+ int n_crlf = 0;
+ int n_lf = 0;
+ int n_cr = 0;
+ int n_nel = 0;
+ int executable = 0;
+
+ size_t last_line_end = (size_t)-1;
+ int has_long_lines = 0;
+
+ nbytes = trim_nuls(buf, nbytes);
+
+ /* If we have fewer than 2 bytes, give up. */
+ if (nbytes <= 1) {
+ rv = 0;
+ goto done;
+ }
+
+ if (ulen > 0 && (ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
+ /* Convert ubuf to UTF-8 and try text soft magic */
+ /* malloc size is a conservative overestimate; could be
+ improved, or at least realloced after conversion. */
+ mlen = ulen * 6;
+ if ((utf8_buf = CAST(unsigned char *, malloc(mlen))) == NULL) {
+ file_oomem(ms, mlen);
+ goto done;
+ }
+ if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen))
+ == NULL)
+ goto done;
+ if ((rv = file_softmagic(ms, utf8_buf,
+ (size_t)(utf8_end - utf8_buf), NULL, NULL,
+ TEXTTEST, text)) == 0)
+ rv = -1;
+ if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))) {
+ rv = rv == -1 ? 0 : 1;
+ goto done;
+ }
+ }
+ if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)))
+ return 0;
+
+ /* Now try to discover other details about the file. */
+ for (i = 0; i < ulen; i++) {
+ if (ubuf[i] == '\n') {
+ if (seen_cr)
+ n_crlf++;
+ else
+ n_lf++;
+ last_line_end = i;
+ } else if (seen_cr)
+ n_cr++;
+
+ seen_cr = (ubuf[i] == '\r');
+ if (seen_cr)
+ last_line_end = i;
+
+ if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
+ n_nel++;
+ last_line_end = i;
+ }
+
+ /* If this line is _longer_ than MAXLINELEN, remember it. */
+ if (i > last_line_end + MAXLINELEN)
+ has_long_lines = 1;
+
+ if (ubuf[i] == '\033')
+ has_escapes = 1;
+ if (ubuf[i] == '\b')
+ has_backspace = 1;
+ }
+
+ /* Beware, if the data has been truncated, the final CR could have
+ been followed by a LF. If we have ms->bytes_max bytes, it indicates
+ that the data might have been truncated, probably even before
+ this function was called. */
+ if (seen_cr && nbytes < ms->bytes_max)
+ n_cr++;
+
+ if (strcmp(type, "binary") == 0) {
+ rv = 0;
+ goto done;
+ }
+ if (mime) {
+ if (!file_printedlen(ms) && (mime & MAGIC_MIME_TYPE) != 0) {
+ if (subtype_mime) {
+ if (file_printf(ms, "%s", subtype_mime) == -1)
+ goto done;
+ } else {
+ if (file_printf(ms, "text/plain") == -1)
+ goto done;
+ }
+ }
+ } else {
+ if (file_printedlen(ms)) {
+ switch (file_replace(ms, " text$", ", ")) {
+ case 0:
+ switch (file_replace(ms, " text executable$",
+ ", ")) {
+ case 0:
+ if (file_printf(ms, ", ") == -1)
+ goto done;
+ break;
+ case -1:
+ goto done;
+ default:
+ executable = 1;
+ break;
+ }
+ break;
+ case -1:
+ goto done;
+ default:
+ break;
+ }
+ }
+
+ if (file_printf(ms, "%s", code) == -1)
+ goto done;
+
+ if (subtype) {
+ if (file_printf(ms, " %s", subtype) == -1)
+ goto done;
+ }
+
+ if (file_printf(ms, " %s", type) == -1)
+ goto done;
+
+ if (executable)
+ if (file_printf(ms, " executable") == -1)
+ goto done;
+
+ if (has_long_lines)
+ if (file_printf(ms, ", with very long lines") == -1)
+ goto done;
+
+ /*
+ * Only report line terminators if we find one other than LF,
+ * or if we find none at all.
+ */
+ if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
+ (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
+ if (file_printf(ms, ", with") == -1)
+ goto done;
+
+ if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) {
+ if (file_printf(ms, " no") == -1)
+ goto done;
+ } else {
+ if (n_crlf) {
+ if (file_printf(ms, " CRLF") == -1)
+ goto done;
+ if (n_cr || n_lf || n_nel)
+ if (file_printf(ms, ",") == -1)
+ goto done;
+ }
+ if (n_cr) {
+ if (file_printf(ms, " CR") == -1)
+ goto done;
+ if (n_lf || n_nel)
+ if (file_printf(ms, ",") == -1)
+ goto done;
+ }
+ if (n_lf) {
+ if (file_printf(ms, " LF") == -1)
+ goto done;
+ if (n_nel)
+ if (file_printf(ms, ",") == -1)
+ goto done;
+ }
+ if (n_nel)
+ if (file_printf(ms, " NEL") == -1)
+ goto done;
+ }
+
+ if (file_printf(ms, " line terminators") == -1)
+ goto done;
+ }
+
+ if (has_escapes)
+ if (file_printf(ms, ", with escape sequences") == -1)
+ goto done;
+ if (has_backspace)
+ if (file_printf(ms, ", with overstriking") == -1)
+ goto done;
+ }
+ rv = 1;
+done:
+ free(utf8_buf);
+
+ return rv;
+}
+
+/*
+ * Encode Unicode string as UTF-8, returning pointer to character
+ * after end of string, or NULL if an invalid character is found.
+ */
+private unsigned char *
+encode_utf8(unsigned char *buf, size_t len, unichar *ubuf, size_t ulen)
+{
+ size_t i;
+ unsigned char *end = buf + len;
+
+ for (i = 0; i < ulen; i++) {
+ if (ubuf[i] <= 0x7f) {
+ if (end - buf < 1)
+ return NULL;
+ *buf++ = (unsigned char)ubuf[i];
+ } else if (ubuf[i] <= 0x7ff) {
+ if (end - buf < 2)
+ return NULL;
+ *buf++ = (unsigned char)((ubuf[i] >> 6) + 0xc0);
+ *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
+ } else if (ubuf[i] <= 0xffff) {
+ if (end - buf < 3)
+ return NULL;
+ *buf++ = (unsigned char)((ubuf[i] >> 12) + 0xe0);
+ *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
+ } else if (ubuf[i] <= 0x1fffff) {
+ if (end - buf < 4)
+ return NULL;
+ *buf++ = (unsigned char)((ubuf[i] >> 18) + 0xf0);
+ *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
+ } else if (ubuf[i] <= 0x3ffffff) {
+ if (end - buf < 5)
+ return NULL;
+ *buf++ = (unsigned char)((ubuf[i] >> 24) + 0xf8);
+ *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
+ } else if (ubuf[i] <= 0x7fffffff) {
+ if (end - buf < 6)
+ return NULL;
+ *buf++ = (unsigned char)((ubuf[i] >> 30) + 0xfc);
+ *buf++ = (unsigned char)(((ubuf[i] >> 24) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 18) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 12) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)(((ubuf[i] >> 6) & 0x3f) + 0x80);
+ *buf++ = (unsigned char)((ubuf[i] & 0x3f) + 0x80);
+ } else /* Invalid character */
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/asctime_r.c b/node_modules/mmmagic/deps/libmagic/src/asctime_r.c
new file mode 100644
index 0000000..3a0ec04
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/asctime_r.c
@@ -0,0 +1,19 @@
+/* $File: asctime_r.c,v 1.1 2012/05/15 17:14:36 christos Exp $ */
+
+#include "file.h"
+#ifndef lint
+FILE_RCSID("@(#)$File: asctime_r.c,v 1.1 2012/05/15 17:14:36 christos Exp $")
+#endif /* lint */
+#include <time.h>
+#include <string.h>
+
+/* asctime_r is not thread-safe anyway */
+char *
+asctime_r(const struct tm *t, char *dst)
+{
+ char *p = asctime(t);
+ if (p == NULL)
+ return NULL;
+ memcpy(dst, p, 26);
+ return dst;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/asprintf.c b/node_modules/mmmagic/deps/libmagic/src/asprintf.c
new file mode 100644
index 0000000..30852d2
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/asprintf.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: asprintf.c,v 1.4 2010/07/21 16:47:17 christos Exp $")
+#endif
+
+int asprintf(char **ptr, const char *fmt, ...)
+{
+ va_list vargs;
+ int retval;
+
+ va_start(vargs, fmt);
+ retval = vasprintf(ptr, fmt, vargs);
+ va_end(vargs);
+
+ return retval;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/cdf.c b/node_modules/mmmagic/deps/libmagic/src/cdf.c
new file mode 100644
index 0000000..0bb22e6
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/cdf.c
@@ -0,0 +1,1629 @@
+/*-
+ * Copyright (c) 2008 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Parse Composite Document Files, the format used in Microsoft Office
+ * document files before they switched to zipped XML.
+ * Info from: http://sc.openoffice.org/compdocfileformat.pdf
+ *
+ * N.B. This is the "Composite Document File" format, and not the
+ * "Compound Document Format", nor the "Channel Definition Format".
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: cdf.c,v 1.106 2017/04/30 17:05:02 christos Exp $")
+#endif
+
+#include <assert.h>
+#ifdef CDF_DEBUG
+#include <err.h>
+#endif
+#include <stdlib.h>
+// XXX: change by mscdex
+//#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef EFTYPE
+#define EFTYPE EINVAL
+#endif
+
+#include "cdf.h"
+
+#ifdef CDF_DEBUG
+#define DPRINTF(a) printf a, fflush(stdout)
+#else
+#define DPRINTF(a)
+#endif
+
+static union {
+ char s[4];
+ uint32_t u;
+} cdf_bo;
+
+#define NEED_SWAP (cdf_bo.u == (uint32_t)0x01020304)
+
+#define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x)))
+#define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x)))
+#define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x)))
+#define CDF_TOLE(x) (/*CONSTCOND*/sizeof(x) == 2 ? \
+ CDF_TOLE2(CAST(uint16_t, x)) : \
+ (/*CONSTCOND*/sizeof(x) == 4 ? \
+ CDF_TOLE4(CAST(uint32_t, x)) : \
+ CDF_TOLE8(CAST(uint64_t, x))))
+#define CDF_GETUINT32(x, y) cdf_getuint32(x, y)
+
+#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n))
+#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n))
+#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u))
+
+
+static void *
+cdf_malloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), size_t n)
+{
+ DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n));
+ return malloc(n);
+}
+
+static void *
+cdf_realloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), void *p, size_t n)
+{
+ DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n));
+ return realloc(p, n);
+}
+
+static void *
+cdf_calloc(const char *file __attribute__((__unused__)),
+ size_t line __attribute__((__unused__)), size_t n, size_t u)
+{
+ DPRINTF(("%s,%zu: %s %zu %zu\n", file, line, __func__, n, u));
+ return calloc(n, u);
+}
+
+/*
+ * swap a short
+ */
+static uint16_t
+_cdf_tole2(uint16_t sv)
+{
+ uint16_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+ d[0] = s[1];
+ d[1] = s[0];
+ return rv;
+}
+
+/*
+ * swap an int
+ */
+static uint32_t
+_cdf_tole4(uint32_t sv)
+{
+ uint32_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = s[1];
+ d[3] = s[0];
+ return rv;
+}
+
+/*
+ * swap a quad
+ */
+static uint64_t
+_cdf_tole8(uint64_t sv)
+{
+ uint64_t rv;
+ uint8_t *s = (uint8_t *)(void *)&sv;
+ uint8_t *d = (uint8_t *)(void *)&rv;
+ d[0] = s[7];
+ d[1] = s[6];
+ d[2] = s[5];
+ d[3] = s[4];
+ d[4] = s[3];
+ d[5] = s[2];
+ d[6] = s[1];
+ d[7] = s[0];
+ return rv;
+}
+
+/*
+ * grab a uint32_t from a possibly unaligned address, and return it in
+ * the native host order.
+ */
+static uint32_t
+cdf_getuint32(const uint8_t *p, size_t offs)
+{
+ uint32_t rv;
+ (void)memcpy(&rv, p + offs * sizeof(uint32_t), sizeof(rv));
+ return CDF_TOLE4(rv);
+}
+
+#define CDF_UNPACK(a) \
+ (void)memcpy(&(a), &buf[len], sizeof(a)), len += sizeof(a)
+#define CDF_UNPACKA(a) \
+ (void)memcpy((a), &buf[len], sizeof(a)), len += sizeof(a)
+
+uint16_t
+cdf_tole2(uint16_t sv)
+{
+ return CDF_TOLE2(sv);
+}
+
+uint32_t
+cdf_tole4(uint32_t sv)
+{
+ return CDF_TOLE4(sv);
+}
+
+uint64_t
+cdf_tole8(uint64_t sv)
+{
+ return CDF_TOLE8(sv);
+}
+
+void
+cdf_swap_header(cdf_header_t *h)
+{
+ size_t i;
+
+ h->h_magic = CDF_TOLE8(h->h_magic);
+ h->h_uuid[0] = CDF_TOLE8(h->h_uuid[0]);
+ h->h_uuid[1] = CDF_TOLE8(h->h_uuid[1]);
+ h->h_revision = CDF_TOLE2(h->h_revision);
+ h->h_version = CDF_TOLE2(h->h_version);
+ h->h_byte_order = CDF_TOLE2(h->h_byte_order);
+ h->h_sec_size_p2 = CDF_TOLE2(h->h_sec_size_p2);
+ h->h_short_sec_size_p2 = CDF_TOLE2(h->h_short_sec_size_p2);
+ h->h_num_sectors_in_sat = CDF_TOLE4(h->h_num_sectors_in_sat);
+ h->h_secid_first_directory = CDF_TOLE4(h->h_secid_first_directory);
+ h->h_min_size_standard_stream =
+ CDF_TOLE4(h->h_min_size_standard_stream);
+ h->h_secid_first_sector_in_short_sat =
+ CDF_TOLE4((uint32_t)h->h_secid_first_sector_in_short_sat);
+ h->h_num_sectors_in_short_sat =
+ CDF_TOLE4(h->h_num_sectors_in_short_sat);
+ h->h_secid_first_sector_in_master_sat =
+ CDF_TOLE4((uint32_t)h->h_secid_first_sector_in_master_sat);
+ h->h_num_sectors_in_master_sat =
+ CDF_TOLE4(h->h_num_sectors_in_master_sat);
+ for (i = 0; i < __arraycount(h->h_master_sat); i++)
+ h->h_master_sat[i] = CDF_TOLE4((uint32_t)h->h_master_sat[i]);
+}
+
+void
+cdf_unpack_header(cdf_header_t *h, char *buf)
+{
+ size_t i;
+ size_t len = 0;
+
+ CDF_UNPACK(h->h_magic);
+ CDF_UNPACKA(h->h_uuid);
+ CDF_UNPACK(h->h_revision);
+ CDF_UNPACK(h->h_version);
+ CDF_UNPACK(h->h_byte_order);
+ CDF_UNPACK(h->h_sec_size_p2);
+ CDF_UNPACK(h->h_short_sec_size_p2);
+ CDF_UNPACKA(h->h_unused0);
+ CDF_UNPACK(h->h_num_sectors_in_sat);
+ CDF_UNPACK(h->h_secid_first_directory);
+ CDF_UNPACKA(h->h_unused1);
+ CDF_UNPACK(h->h_min_size_standard_stream);
+ CDF_UNPACK(h->h_secid_first_sector_in_short_sat);
+ CDF_UNPACK(h->h_num_sectors_in_short_sat);
+ CDF_UNPACK(h->h_secid_first_sector_in_master_sat);
+ CDF_UNPACK(h->h_num_sectors_in_master_sat);
+ for (i = 0; i < __arraycount(h->h_master_sat); i++)
+ CDF_UNPACK(h->h_master_sat[i]);
+}
+
+void
+cdf_swap_dir(cdf_directory_t *d)
+{
+ d->d_namelen = CDF_TOLE2(d->d_namelen);
+ d->d_left_child = CDF_TOLE4((uint32_t)d->d_left_child);
+ d->d_right_child = CDF_TOLE4((uint32_t)d->d_right_child);
+ d->d_storage = CDF_TOLE4((uint32_t)d->d_storage);
+ d->d_storage_uuid[0] = CDF_TOLE8(d->d_storage_uuid[0]);
+ d->d_storage_uuid[1] = CDF_TOLE8(d->d_storage_uuid[1]);
+ d->d_flags = CDF_TOLE4(d->d_flags);
+ d->d_created = CDF_TOLE8((uint64_t)d->d_created);
+ d->d_modified = CDF_TOLE8((uint64_t)d->d_modified);
+ d->d_stream_first_sector = CDF_TOLE4((uint32_t)d->d_stream_first_sector);
+ d->d_size = CDF_TOLE4(d->d_size);
+}
+
+void
+cdf_swap_class(cdf_classid_t *d)
+{
+ d->cl_dword = CDF_TOLE4(d->cl_dword);
+ d->cl_word[0] = CDF_TOLE2(d->cl_word[0]);
+ d->cl_word[1] = CDF_TOLE2(d->cl_word[1]);
+}
+
+void
+cdf_unpack_dir(cdf_directory_t *d, char *buf)
+{
+ size_t len = 0;
+
+ CDF_UNPACKA(d->d_name);
+ CDF_UNPACK(d->d_namelen);
+ CDF_UNPACK(d->d_type);
+ CDF_UNPACK(d->d_color);
+ CDF_UNPACK(d->d_left_child);
+ CDF_UNPACK(d->d_right_child);
+ CDF_UNPACK(d->d_storage);
+ CDF_UNPACKA(d->d_storage_uuid);
+ CDF_UNPACK(d->d_flags);
+ CDF_UNPACK(d->d_created);
+ CDF_UNPACK(d->d_modified);
+ CDF_UNPACK(d->d_stream_first_sector);
+ CDF_UNPACK(d->d_size);
+ CDF_UNPACK(d->d_unused0);
+}
+
+int
+cdf_zero_stream(cdf_stream_t *scn)
+{
+ scn->sst_len = 0;
+ scn->sst_dirlen = 0;
+ scn->sst_ss = 0;
+ free(scn->sst_tab);
+ scn->sst_tab = NULL;
+ return -1;
+}
+
+static size_t
+cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h)
+{
+ size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
+ CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ assert(ss == sst->sst_ss);
+ return sst->sst_ss;
+}
+
+static int
+cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h,
+ const void *p, size_t tail, int line)
+{
+ const char *b = (const char *)sst->sst_tab;
+ const char *e = ((const char *)p) + tail;
+ size_t ss = cdf_check_stream(sst, h);
+ /*LINTED*/(void)&line;
+ if (e >= b && (size_t)(e - b) <= ss * sst->sst_len)
+ return 0;
+ DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u"
+ " > %" SIZE_T_FORMAT "u [%" SIZE_T_FORMAT "u %"
+ SIZE_T_FORMAT "u]\n", line, b, e, (size_t)(e - b),
+ ss * sst->sst_len, ss, sst->sst_len));
+ errno = EFTYPE;
+ return -1;
+}
+
+static ssize_t
+cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
+{
+ size_t siz = (size_t)off + len;
+
+ if ((off_t)(off + len) != (off_t)siz)
+ goto out;
+
+ if (info->i_buf != NULL && info->i_len >= siz) {
+ (void)memcpy(buf, &info->i_buf[off], len);
+ return (ssize_t)len;
+ }
+
+ if (info->i_fd == -1)
+ goto out;
+
+ if (pread(info->i_fd, buf, len, off) != (ssize_t)len)
+ return -1;
+
+ return (ssize_t)len;
+out:
+ errno = EINVAL;
+ return -1;
+}
+
+int
+cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
+{
+ char buf[512];
+
+ (void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
+ if (cdf_read(info, (off_t)0, buf, sizeof(buf)) == -1)
+ return -1;
+ cdf_unpack_header(h, buf);
+ cdf_swap_header(h);
+ if (h->h_magic != CDF_MAGIC) {
+ DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#"
+ INT64_T_FORMAT "x\n",
+ (unsigned long long)h->h_magic,
+ (unsigned long long)CDF_MAGIC));
+ goto out;
+ }
+ if (h->h_sec_size_p2 > 20) {
+ DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2));
+ goto out;
+ }
+ if (h->h_short_sec_size_p2 > 20) {
+ DPRINTF(("Bad short sector size %hu\n",
+ h->h_short_sec_size_p2));
+ goto out;
+ }
+ return 0;
+out:
+ errno = EFTYPE;
+ return -1;
+}
+
+
+ssize_t
+cdf_read_sector(const cdf_info_t *info, void *buf, size_t offs, size_t len,
+ const cdf_header_t *h, cdf_secid_t id)
+{
+ size_t ss = CDF_SEC_SIZE(h);
+ size_t pos = CDF_SEC_POS(h, id);
+ assert(ss == len);
+ return cdf_read(info, (off_t)pos, ((char *)buf) + offs, len);
+}
+
+ssize_t
+cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
+ size_t len, const cdf_header_t *h, cdf_secid_t id)
+{
+ size_t ss = CDF_SHORT_SEC_SIZE(h);
+ size_t pos = CDF_SHORT_SEC_POS(h, id);
+ assert(ss == len);
+ if (pos + len > CDF_SEC_SIZE(h) * sst->sst_len) {
+ DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %"
+ SIZE_T_FORMAT "u\n",
+ pos + len, CDF_SEC_SIZE(h) * sst->sst_len));
+ goto out;
+ }
+ (void)memcpy(((char *)buf) + offs,
+ ((const char *)sst->sst_tab) + pos, len);
+ return len;
+out:
+ errno = EFTYPE;
+ return -1;
+}
+
+/*
+ * Read the sector allocation table.
+ */
+int
+cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
+{
+ size_t i, j, k;
+ size_t ss = CDF_SEC_SIZE(h);
+ cdf_secid_t *msa, mid, sec;
+ size_t nsatpersec = (ss / sizeof(mid)) - 1;
+
+ for (i = 0; i < __arraycount(h->h_master_sat); i++)
+ if (h->h_master_sat[i] == CDF_SECID_FREE)
+ break;
+
+#define CDF_SEC_LIMIT (UINT32_MAX / (8 * ss))
+ if ((nsatpersec > 0 &&
+ h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) ||
+ i > CDF_SEC_LIMIT) {
+ DPRINTF(("Number of sectors in master SAT too big %u %"
+ SIZE_T_FORMAT "u\n", h->h_num_sectors_in_master_sat, i));
+ errno = EFTYPE;
+ return -1;
+ }
+
+ sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
+ DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n",
+ sat->sat_len, ss));
+ if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss)))
+ == NULL)
+ return -1;
+
+ for (i = 0; i < __arraycount(h->h_master_sat); i++) {
+ if (h->h_master_sat[i] < 0)
+ break;
+ if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
+ h->h_master_sat[i]) != (ssize_t)ss) {
+ DPRINTF(("Reading sector %d", h->h_master_sat[i]));
+ goto out1;
+ }
+ }
+
+ if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL)
+ goto out1;
+
+ mid = h->h_secid_first_sector_in_master_sat;
+ for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
+ if (mid < 0)
+ goto out;
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Reading master sector loop limit"));
+ goto out3;
+ }
+ if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
+ DPRINTF(("Reading master sector %d", mid));
+ goto out2;
+ }
+ for (k = 0; k < nsatpersec; k++, i++) {
+ sec = CDF_TOLE4((uint32_t)msa[k]);
+ if (sec < 0)
+ goto out;
+ if (i >= sat->sat_len) {
+ DPRINTF(("Out of bounds reading MSA %" SIZE_T_FORMAT
+ "u >= %" SIZE_T_FORMAT "u", i, sat->sat_len));
+ goto out3;
+ }
+ if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
+ sec) != (ssize_t)ss) {
+ DPRINTF(("Reading sector %d",
+ CDF_TOLE4(msa[k])));
+ goto out2;
+ }
+ }
+ mid = CDF_TOLE4((uint32_t)msa[nsatpersec]);
+ }
+out:
+ sat->sat_len = i;
+ free(msa);
+ return 0;
+out3:
+ errno = EFTYPE;
+out2:
+ free(msa);
+out1:
+ free(sat->sat_tab);
+ return -1;
+}
+
+size_t
+cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
+{
+ size_t i, j;
+ cdf_secid_t maxsector = (cdf_secid_t)((sat->sat_len * size)
+ / sizeof(maxsector));
+
+ DPRINTF(("Chain:"));
+ if (sid == CDF_SECID_END_OF_CHAIN) {
+ /* 0-length chain. */
+ DPRINTF((" empty\n"));
+ return 0;
+ }
+
+ for (j = i = 0; sid >= 0; i++, j++) {
+ DPRINTF((" %d", sid));
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Counting chain loop limit"));
+ goto out;
+ }
+ if (sid >= maxsector) {
+ DPRINTF(("Sector %d >= %d\n", sid, maxsector));
+ goto out;
+ }
+ sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
+ }
+ if (i == 0) {
+ DPRINTF((" none, sid: %d\n", sid));
+ goto out;
+
+ }
+ DPRINTF(("\n"));
+ return i;
+out:
+ errno = EFTYPE;
+ return (size_t)-1;
+}
+
+int
+cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, cdf_secid_t sid, size_t len, cdf_stream_t *scn)
+{
+ size_t ss = CDF_SEC_SIZE(h), i, j;
+ ssize_t nr;
+ scn->sst_tab = NULL;
+ scn->sst_len = cdf_count_chain(sat, sid, ss);
+ scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len);
+ scn->sst_ss = ss;
+
+ if (sid == CDF_SECID_END_OF_CHAIN || len == 0)
+ return cdf_zero_stream(scn);
+
+ if (scn->sst_len == (size_t)-1)
+ goto out;
+
+ scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
+ if (scn->sst_tab == NULL)
+ return cdf_zero_stream(scn);
+
+ for (j = i = 0; sid >= 0; i++, j++) {
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Read long sector chain loop limit"));
+ goto out;
+ }
+ if (i >= scn->sst_len) {
+ DPRINTF(("Out of bounds reading long sector chain "
+ "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
+ scn->sst_len));
+ goto out;
+ }
+ if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
+ sid)) != (ssize_t)ss) {
+ if (i == scn->sst_len - 1 && nr > 0) {
+ /* Last sector might be truncated */
+ return 0;
+ }
+ DPRINTF(("Reading long sector chain %d", sid));
+ goto out;
+ }
+ sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
+ }
+ return 0;
+out:
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
+}
+
+int
+cdf_read_short_sector_chain(const cdf_header_t *h,
+ const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ cdf_secid_t sid, size_t len, cdf_stream_t *scn)
+{
+ size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
+ scn->sst_tab = NULL;
+ scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
+ scn->sst_dirlen = len;
+ scn->sst_ss = ss;
+
+ if (scn->sst_len == (size_t)-1)
+ goto out;
+
+ scn->sst_tab = CDF_CALLOC(scn->sst_len, ss);
+ if (scn->sst_tab == NULL)
+ return cdf_zero_stream(scn);
+
+ for (j = i = 0; sid >= 0; i++, j++) {
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Read short sector chain loop limit"));
+ goto out;
+ }
+ if (i >= scn->sst_len) {
+ DPRINTF(("Out of bounds reading short sector chain "
+ "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n",
+ i, scn->sst_len));
+ goto out;
+ }
+ if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
+ sid) != (ssize_t)ss) {
+ DPRINTF(("Reading short sector chain %d", sid));
+ goto out;
+ }
+ sid = CDF_TOLE4((uint32_t)ssat->sat_tab[sid]);
+ }
+ return 0;
+out:
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
+}
+
+int
+cdf_read_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ cdf_secid_t sid, size_t len, cdf_stream_t *scn)
+{
+
+ if (len < h->h_min_size_standard_stream && sst->sst_tab != NULL)
+ return cdf_read_short_sector_chain(h, ssat, sst, sid, len,
+ scn);
+ else
+ return cdf_read_long_sector_chain(info, h, sat, sid, len, scn);
+}
+
+int
+cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, cdf_dir_t *dir)
+{
+ size_t i, j;
+ size_t ss = CDF_SEC_SIZE(h), ns, nd;
+ char *buf;
+ cdf_secid_t sid = h->h_secid_first_directory;
+
+ ns = cdf_count_chain(sat, sid, ss);
+ if (ns == (size_t)-1)
+ return -1;
+
+ nd = ss / CDF_DIRECTORY_SIZE;
+
+ dir->dir_len = ns * nd;
+ dir->dir_tab = CAST(cdf_directory_t *,
+ CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0])));
+ if (dir->dir_tab == NULL)
+ return -1;
+
+ if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) {
+ free(dir->dir_tab);
+ return -1;
+ }
+
+ for (j = i = 0; i < ns; i++, j++) {
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Read dir loop limit"));
+ goto out;
+ }
+ if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
+ DPRINTF(("Reading directory sector %d", sid));
+ goto out;
+ }
+ for (j = 0; j < nd; j++) {
+ cdf_unpack_dir(&dir->dir_tab[i * nd + j],
+ &buf[j * CDF_DIRECTORY_SIZE]);
+ }
+ sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
+ }
+ if (NEED_SWAP)
+ for (i = 0; i < dir->dir_len; i++)
+ cdf_swap_dir(&dir->dir_tab[i]);
+ free(buf);
+ return 0;
+out:
+ free(dir->dir_tab);
+ free(buf);
+ errno = EFTYPE;
+ return -1;
+}
+
+
+int
+cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, cdf_sat_t *ssat)
+{
+ size_t i, j;
+ size_t ss = CDF_SEC_SIZE(h);
+ cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
+
+ ssat->sat_tab = NULL;
+ ssat->sat_len = cdf_count_chain(sat, sid, ss);
+ if (ssat->sat_len == (size_t)-1)
+ goto out;
+
+ ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss));
+ if (ssat->sat_tab == NULL)
+ goto out1;
+
+ for (j = i = 0; sid >= 0; i++, j++) {
+ if (j >= CDF_LOOP_LIMIT) {
+ DPRINTF(("Read short sat sector loop limit"));
+ goto out;
+ }
+ if (i >= ssat->sat_len) {
+ DPRINTF(("Out of bounds reading short sector chain "
+ "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
+ ssat->sat_len));
+ goto out;
+ }
+ if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
+ (ssize_t)ss) {
+ DPRINTF(("Reading short sat sector %d", sid));
+ goto out1;
+ }
+ sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
+ }
+ return 0;
+out:
+ errno = EFTYPE;
+out1:
+ free(ssat->sat_tab);
+ return -1;
+}
+
+int
+cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_dir_t *dir, cdf_stream_t *scn,
+ const cdf_directory_t **root)
+{
+ size_t i;
+ const cdf_directory_t *d;
+
+ *root = NULL;
+ for (i = 0; i < dir->dir_len; i++)
+ if (dir->dir_tab[i].d_type == CDF_DIR_TYPE_ROOT_STORAGE)
+ break;
+
+ /* If the it is not there, just fake it; some docs don't have it */
+ if (i == dir->dir_len) {
+ DPRINTF(("Cannot find root storage dir\n"));
+ goto out;
+ }
+ d = &dir->dir_tab[i];
+ *root = d;
+
+ /* If the it is not there, just fake it; some docs don't have it */
+ if (d->d_stream_first_sector < 0) {
+ DPRINTF(("No first secror in dir\n"));
+ goto out;
+ }
+
+ return cdf_read_long_sector_chain(info, h, sat,
+ d->d_stream_first_sector, d->d_size, scn);
+out:
+ scn->sst_tab = NULL;
+ (void)cdf_zero_stream(scn);
+ return 0;
+}
+
+static int
+cdf_namecmp(const char *d, const uint16_t *s, size_t l)
+{
+ for (; l--; d++, s++)
+ if (*d != CDF_TOLE2(*s))
+ return (unsigned char)*d - CDF_TOLE2(*s);
+ return 0;
+}
+
+int
+cdf_read_doc_summary_info(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ const cdf_dir_t *dir, cdf_stream_t *scn)
+{
+ return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
+ "\05DocumentSummaryInformation", scn);
+}
+
+int
+cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ const cdf_dir_t *dir, cdf_stream_t *scn)
+{
+ return cdf_read_user_stream(info, h, sat, ssat, sst, dir,
+ "\05SummaryInformation", scn);
+}
+
+int
+cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ const cdf_dir_t *dir, const char *name, cdf_stream_t *scn)
+{
+ const cdf_directory_t *d;
+ int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM);
+
+ if (i <= 0) {
+ memset(scn, 0, sizeof(*scn));
+ return -1;
+ }
+
+ d = &dir->dir_tab[i - 1];
+ return cdf_read_sector_chain(info, h, sat, ssat, sst,
+ d->d_stream_first_sector, d->d_size, scn);
+}
+
+int
+cdf_find_stream(const cdf_dir_t *dir, const char *name, int type)
+{
+ size_t i, name_len = strlen(name) + 1;
+
+ for (i = dir->dir_len; i > 0; i--)
+ if (dir->dir_tab[i - 1].d_type == type &&
+ cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len)
+ == 0)
+ break;
+ if (i > 0)
+ return CAST(int, i);
+
+ DPRINTF(("Cannot find type %d `%s'\n", type, name));
+ errno = ESRCH;
+ return 0;
+}
+
+#define CDF_SHLEN_LIMIT (UINT32_MAX / 8)
+#define CDF_PROP_LIMIT (UINT32_MAX / (8 * sizeof(cdf_property_info_t)))
+
+static const void *
+cdf_offset(const void *p, size_t l)
+{
+ return CAST(const void *, CAST(const uint8_t *, p) + l);
+}
+
+static const uint8_t *
+cdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h,
+ const uint8_t *p, const uint8_t *e, size_t i)
+{
+ size_t tail = (i << 1) + 1;
+ size_t ofs;
+ const uint8_t *q;
+
+ if (p >= e) {
+ DPRINTF(("Past end %p < %p\n", e, p));
+ return NULL;
+ }
+ if (cdf_check_stream_offset(sst, h, p, (tail + 1) * sizeof(uint32_t),
+ __LINE__) == -1)
+ return NULL;
+ ofs = CDF_GETUINT32(p, tail);
+ q = CAST(const uint8_t *, cdf_offset(CAST(const void *, p),
+ ofs - 2 * sizeof(uint32_t)));
+
+ if (q < p) {
+ DPRINTF(("Wrapped around %p < %p\n", q, p));
+ return NULL;
+ }
+
+ if (q >= e) {
+ DPRINTF(("Ran off the end %p >= %p\n", q, e));
+ return NULL;
+ }
+ return q;
+}
+
+static cdf_property_info_t *
+cdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr)
+{
+ cdf_property_info_t *inp;
+ size_t newcount = *maxcount + incr;
+
+ if (newcount > CDF_PROP_LIMIT) {
+ DPRINTF(("exceeded property limit %zu > %zu\n",
+ newcount, CDF_PROP_LIMIT));
+ goto out;
+ }
+ inp = CAST(cdf_property_info_t *,
+ CDF_REALLOC(*info, newcount * sizeof(*inp)));
+ if (inp == NULL)
+ goto out;
+
+ *info = inp;
+ *maxcount = newcount;
+ return inp;
+out:
+ free(*info);
+ *maxcount = 0;
+ *info = NULL;
+ return NULL;
+}
+
+static int
+cdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e,
+ size_t len)
+{
+ if (inp->pi_type & CDF_VECTOR)
+ return 0;
+
+ if ((size_t)(CAST(const char *, e) - CAST(const char *, p)) < len)
+ return 0;
+
+ (void)memcpy(&inp->pi_val, p, len);
+
+ switch (len) {
+ case 2:
+ inp->pi_u16 = CDF_TOLE2(inp->pi_u16);
+ break;
+ case 4:
+ inp->pi_u32 = CDF_TOLE4(inp->pi_u32);
+ break;
+ case 8:
+ inp->pi_u64 = CDF_TOLE8(inp->pi_u64);
+ break;
+ default:
+ abort();
+ }
+ return 1;
+}
+
+int
+cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
+ uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount)
+{
+ const cdf_section_header_t *shp;
+ cdf_section_header_t sh;
+ const uint8_t *p, *q, *e;
+ size_t i, o4, nelements, j, slen, left;
+ cdf_property_info_t *inp;
+
+ if (offs > UINT32_MAX / 4) {
+ errno = EFTYPE;
+ goto out;
+ }
+ shp = CAST(const cdf_section_header_t *,
+ cdf_offset(sst->sst_tab, offs));
+ if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1)
+ goto out;
+ sh.sh_len = CDF_TOLE4(shp->sh_len);
+ if (sh.sh_len > CDF_SHLEN_LIMIT) {
+ errno = EFTYPE;
+ goto out;
+ }
+
+ if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1)
+ goto out;
+
+ sh.sh_properties = CDF_TOLE4(shp->sh_properties);
+ DPRINTF(("section len: %u properties %u\n", sh.sh_len,
+ sh.sh_properties));
+ if (sh.sh_properties > CDF_PROP_LIMIT)
+ goto out;
+ inp = cdf_grow_info(info, maxcount, sh.sh_properties);
+ if (inp == NULL)
+ goto out;
+ inp += *count;
+ *count += sh.sh_properties;
+ p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh)));
+ e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len));
+ if (p >= e || cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1)
+ goto out;
+
+ for (i = 0; i < sh.sh_properties; i++) {
+ if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL)
+ goto out;
+ inp[i].pi_id = CDF_GETUINT32(p, i << 1);
+ left = CAST(size_t, e - q);
+ if (left < sizeof(uint32_t)) {
+ DPRINTF(("short info (no type)_\n"));
+ goto out;
+ }
+ inp[i].pi_type = CDF_GETUINT32(q, 0);
+ DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n",
+ i, inp[i].pi_id, inp[i].pi_type, q - p, offs));
+ if (inp[i].pi_type & CDF_VECTOR) {
+ if (left < sizeof(uint32_t) * 2) {
+ DPRINTF(("missing CDF_VECTOR length\n"));
+ goto out;
+ }
+ nelements = CDF_GETUINT32(q, 1);
+ if (nelements == 0) {
+ DPRINTF(("CDF_VECTOR with nelements == 0\n"));
+ goto out;
+ }
+ slen = 2;
+ } else {
+ nelements = 1;
+ slen = 1;
+ }
+ o4 = slen * sizeof(uint32_t);
+ if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED))
+ goto unknown;
+ switch (inp[i].pi_type & CDF_TYPEMASK) {
+ case CDF_NULL:
+ case CDF_EMPTY:
+ break;
+ case CDF_SIGNED16:
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t)))
+ goto unknown;
+ break;
+ case CDF_SIGNED32:
+ case CDF_BOOL:
+ case CDF_UNSIGNED32:
+ case CDF_FLOAT:
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t)))
+ goto unknown;
+ break;
+ case CDF_SIGNED64:
+ case CDF_UNSIGNED64:
+ case CDF_DOUBLE:
+ case CDF_FILETIME:
+ if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t)))
+ goto unknown;
+ break;
+ case CDF_LENGTH32_STRING:
+ case CDF_LENGTH32_WSTRING:
+ if (nelements > 1) {
+ size_t nelem = inp - *info;
+ inp = cdf_grow_info(info, maxcount, nelements);
+ if (inp == NULL)
+ goto out;
+ inp += nelem;
+ }
+ DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n",
+ nelements));
+ for (j = 0; j < nelements && i < sh.sh_properties;
+ j++, i++)
+ {
+ uint32_t l;
+
+ if (o4 + sizeof(uint32_t) > left)
+ goto out;
+
+ l = CDF_GETUINT32(q, slen);
+ o4 += sizeof(uint32_t);
+ if (o4 + l > left)
+ goto out;
+
+ inp[i].pi_str.s_len = l;
+ inp[i].pi_str.s_buf = CAST(const char *,
+ CAST(const void *, &q[o4]));
+
+ DPRINTF(("o=%zu l=%d(%" SIZE_T_FORMAT
+ "u), t=%zu s=%s\n", o4, l,
+ CDF_ROUND(l, sizeof(l)), left,
+ inp[i].pi_str.s_buf));
+
+ if (l & 1)
+ l++;
+
+ slen += l >> 1;
+ o4 = slen * sizeof(uint32_t);
+ }
+ i--;
+ break;
+ case CDF_CLIPBOARD:
+ if (inp[i].pi_type & CDF_VECTOR)
+ goto unknown;
+ break;
+ default:
+ unknown:
+ memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val));
+ DPRINTF(("Don't know how to deal with %#x\n",
+ inp[i].pi_type));
+ break;
+ }
+ }
+ return 0;
+out:
+ free(*info);
+ *info = NULL;
+ *count = 0;
+ *maxcount = 0;
+ errno = EFTYPE;
+ return -1;
+}
+
+int
+cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h,
+ cdf_summary_info_header_t *ssi, cdf_property_info_t **info, size_t *count)
+{
+ size_t maxcount;
+ const cdf_summary_info_header_t *si =
+ CAST(const cdf_summary_info_header_t *, sst->sst_tab);
+ const cdf_section_declaration_t *sd =
+ CAST(const cdf_section_declaration_t *, (const void *)
+ ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET));
+
+ if (cdf_check_stream_offset(sst, h, si, sizeof(*si), __LINE__) == -1 ||
+ cdf_check_stream_offset(sst, h, sd, sizeof(*sd), __LINE__) == -1)
+ return -1;
+ ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
+ ssi->si_os_version = CDF_TOLE2(si->si_os_version);
+ ssi->si_os = CDF_TOLE2(si->si_os);
+ ssi->si_class = si->si_class;
+ cdf_swap_class(&ssi->si_class);
+ ssi->si_count = CDF_TOLE4(si->si_count);
+ *count = 0;
+ maxcount = 0;
+ *info = NULL;
+ if (cdf_read_property_info(sst, h, CDF_TOLE4(sd->sd_offset), info,
+ count, &maxcount) == -1)
+ return -1;
+ return 0;
+}
+
+
+#define extract_catalog_field(t, f, l) \
+ if (b + l + sizeof(cep->f) > eb) { \
+ cep->ce_namlen = 0; \
+ break; \
+ } \
+ memcpy(&cep->f, b + (l), sizeof(cep->f)); \
+ ce[i].f = CAST(t, CDF_TOLE(cep->f))
+
+int
+cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
+ cdf_catalog_t **cat)
+{
+ size_t ss = cdf_check_stream(sst, h);
+ const char *b = CAST(const char *, sst->sst_tab);
+ const char *nb, *eb = b + ss * sst->sst_len;
+ size_t nr, i, j, k;
+ cdf_catalog_entry_t *ce;
+ uint16_t reclen;
+ const uint16_t *np;
+
+ for (nr = 0;; nr++) {
+ memcpy(&reclen, b, sizeof(reclen));
+ reclen = CDF_TOLE2(reclen);
+ if (reclen == 0)
+ break;
+ b += reclen;
+ if (b > eb)
+ break;
+ }
+ if (nr == 0)
+ return -1;
+ nr--;
+ *cat = CAST(cdf_catalog_t *,
+ CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
+ if (*cat == NULL)
+ return -1;
+ ce = (*cat)->cat_e;
+ memset(ce, 0, nr * sizeof(*ce));
+ b = CAST(const char *, sst->sst_tab);
+ for (j = i = 0; i < nr; b += reclen) {
+ cdf_catalog_entry_t *cep = &ce[j];
+ uint16_t rlen;
+
+ extract_catalog_field(uint16_t, ce_namlen, 0);
+ extract_catalog_field(uint16_t, ce_num, 4);
+ extract_catalog_field(uint64_t, ce_timestamp, 8);
+ reclen = cep->ce_namlen;
+
+ if (reclen < 14) {
+ cep->ce_namlen = 0;
+ continue;
+ }
+
+ cep->ce_namlen = __arraycount(cep->ce_name) - 1;
+ rlen = reclen - 14;
+ if (cep->ce_namlen > rlen)
+ cep->ce_namlen = rlen;
+
+ np = CAST(const uint16_t *, CAST(const void *, (b + 16)));
+ nb = CAST(const char *, CAST(const void *,
+ (np + cep->ce_namlen)));
+ if (nb > eb) {
+ cep->ce_namlen = 0;
+ break;
+ }
+
+ for (k = 0; k < cep->ce_namlen; k++)
+ cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */
+ cep->ce_name[cep->ce_namlen] = 0;
+ j = i;
+ i++;
+ }
+ (*cat)->cat_num = j;
+ return 0;
+}
+
+int
+cdf_print_classid(char *buf, size_t buflen, const cdf_classid_t *id)
+{
+ return snprintf(buf, buflen, "%.8x-%.4x-%.4x-%.2x%.2x-"
+ "%.2x%.2x%.2x%.2x%.2x%.2x", id->cl_dword, id->cl_word[0],
+ id->cl_word[1], id->cl_two[0], id->cl_two[1], id->cl_six[0],
+ id->cl_six[1], id->cl_six[2], id->cl_six[3], id->cl_six[4],
+ id->cl_six[5]);
+}
+
+static const struct {
+ uint32_t v;
+ const char *n;
+} vn[] = {
+ { CDF_PROPERTY_CODE_PAGE, "Code page" },
+ { CDF_PROPERTY_TITLE, "Title" },
+ { CDF_PROPERTY_SUBJECT, "Subject" },
+ { CDF_PROPERTY_AUTHOR, "Author" },
+ { CDF_PROPERTY_KEYWORDS, "Keywords" },
+ { CDF_PROPERTY_COMMENTS, "Comments" },
+ { CDF_PROPERTY_TEMPLATE, "Template" },
+ { CDF_PROPERTY_LAST_SAVED_BY, "Last Saved By" },
+ { CDF_PROPERTY_REVISION_NUMBER, "Revision Number" },
+ { CDF_PROPERTY_TOTAL_EDITING_TIME, "Total Editing Time" },
+ { CDF_PROPERTY_LAST_PRINTED, "Last Printed" },
+ { CDF_PROPERTY_CREATE_TIME, "Create Time/Date" },
+ { CDF_PROPERTY_LAST_SAVED_TIME, "Last Saved Time/Date" },
+ { CDF_PROPERTY_NUMBER_OF_PAGES, "Number of Pages" },
+ { CDF_PROPERTY_NUMBER_OF_WORDS, "Number of Words" },
+ { CDF_PROPERTY_NUMBER_OF_CHARACTERS, "Number of Characters" },
+ { CDF_PROPERTY_THUMBNAIL, "Thumbnail" },
+ { CDF_PROPERTY_NAME_OF_APPLICATION, "Name of Creating Application" },
+ { CDF_PROPERTY_SECURITY, "Security" },
+ { CDF_PROPERTY_LOCALE_ID, "Locale ID" },
+};
+
+int
+cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p)
+{
+ size_t i;
+
+ for (i = 0; i < __arraycount(vn); i++)
+ if (vn[i].v == p)
+ return snprintf(buf, bufsiz, "%s", vn[i].n);
+ return snprintf(buf, bufsiz, "%#x", p);
+}
+
+int
+cdf_print_elapsed_time(char *buf, size_t bufsiz, cdf_timestamp_t ts)
+{
+ int len = 0;
+ int days, hours, mins, secs;
+
+ ts /= CDF_TIME_PREC;
+ secs = (int)(ts % 60);
+ ts /= 60;
+ mins = (int)(ts % 60);
+ ts /= 60;
+ hours = (int)(ts % 24);
+ ts /= 24;
+ days = (int)ts;
+
+ if (days) {
+ len += snprintf(buf + len, bufsiz - len, "%dd+", days);
+ if ((size_t)len >= bufsiz)
+ return len;
+ }
+
+ if (days || hours) {
+ len += snprintf(buf + len, bufsiz - len, "%.2d:", hours);
+ if ((size_t)len >= bufsiz)
+ return len;
+ }
+
+ len += snprintf(buf + len, bufsiz - len, "%.2d:", mins);
+ if ((size_t)len >= bufsiz)
+ return len;
+
+ len += snprintf(buf + len, bufsiz - len, "%.2d", secs);
+ return len;
+}
+
+char *
+cdf_u16tos8(char *buf, size_t len, const uint16_t *p)
+{
+ size_t i;
+ for (i = 0; i < len && p[i]; i++)
+ buf[i] = (char)p[i];
+ buf[i] = '\0';
+ return buf;
+}
+
+#ifdef CDF_DEBUG
+void
+cdf_dump_header(const cdf_header_t *h)
+{
+ size_t i;
+
+#define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
+#define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
+ h->h_ ## b, 1 << h->h_ ## b)
+ DUMP("%d", revision);
+ DUMP("%d", version);
+ DUMP("%#x", byte_order);
+ DUMP2("%d", sec_size_p2);
+ DUMP2("%d", short_sec_size_p2);
+ DUMP("%d", num_sectors_in_sat);
+ DUMP("%d", secid_first_directory);
+ DUMP("%d", min_size_standard_stream);
+ DUMP("%d", secid_first_sector_in_short_sat);
+ DUMP("%d", num_sectors_in_short_sat);
+ DUMP("%d", secid_first_sector_in_master_sat);
+ DUMP("%d", num_sectors_in_master_sat);
+ for (i = 0; i < __arraycount(h->h_master_sat); i++) {
+ if (h->h_master_sat[i] == CDF_SECID_FREE)
+ break;
+ (void)fprintf(stderr, "%35.35s[%.3" SIZE_T_FORMAT "u] = %d\n",
+ "master_sat", i, h->h_master_sat[i]);
+ }
+}
+
+void
+cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size)
+{
+ size_t i, j, s = size / sizeof(cdf_secid_t);
+
+ for (i = 0; i < sat->sat_len; i++) {
+ (void)fprintf(stderr, "%s[%" SIZE_T_FORMAT "u]:\n%.6"
+ SIZE_T_FORMAT "u: ", prefix, i, i * s);
+ for (j = 0; j < s; j++) {
+ (void)fprintf(stderr, "%5d, ",
+ CDF_TOLE4(sat->sat_tab[s * i + j]));
+ if ((j + 1) % 10 == 0)
+ (void)fprintf(stderr, "\n%.6" SIZE_T_FORMAT
+ "u: ", i * s + j + 1);
+ }
+ (void)fprintf(stderr, "\n");
+ }
+}
+
+void
+cdf_dump(const void *v, size_t len)
+{
+ size_t i, j;
+ const unsigned char *p = v;
+ char abuf[16];
+
+ (void)fprintf(stderr, "%.4x: ", 0);
+ for (i = 0, j = 0; i < len; i++, p++) {
+ (void)fprintf(stderr, "%.2x ", *p);
+ abuf[j++] = isprint(*p) ? *p : '.';
+ if (j == 16) {
+ j = 0;
+ abuf[15] = '\0';
+ (void)fprintf(stderr, "%s\n%.4" SIZE_T_FORMAT "x: ",
+ abuf, i + 1);
+ }
+ }
+ (void)fprintf(stderr, "\n");
+}
+
+void
+cdf_dump_stream(const cdf_stream_t *sst)
+{
+ size_t ss = sst->sst_ss;
+ cdf_dump(sst->sst_tab, ss * sst->sst_len);
+}
+
+void
+cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h,
+ const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst,
+ const cdf_dir_t *dir)
+{
+ size_t i, j;
+ cdf_directory_t *d;
+ char name[__arraycount(d->d_name)];
+ cdf_stream_t scn;
+ struct timespec ts;
+
+ static const char *types[] = { "empty", "user storage",
+ "user stream", "lockbytes", "property", "root storage" };
+
+ for (i = 0; i < dir->dir_len; i++) {
+ char buf[26];
+ d = &dir->dir_tab[i];
+ for (j = 0; j < sizeof(name); j++)
+ name[j] = (char)CDF_TOLE2(d->d_name[j]);
+ (void)fprintf(stderr, "Directory %" SIZE_T_FORMAT "u: %s\n",
+ i, name);
+ if (d->d_type < __arraycount(types))
+ (void)fprintf(stderr, "Type: %s\n", types[d->d_type]);
+ else
+ (void)fprintf(stderr, "Type: %d\n", d->d_type);
+ (void)fprintf(stderr, "Color: %s\n",
+ d->d_color ? "black" : "red");
+ (void)fprintf(stderr, "Left child: %d\n", d->d_left_child);
+ (void)fprintf(stderr, "Right child: %d\n", d->d_right_child);
+ (void)fprintf(stderr, "Flags: %#x\n", d->d_flags);
+ cdf_timestamp_to_timespec(&ts, d->d_created);
+ (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf));
+ cdf_timestamp_to_timespec(&ts, d->d_modified);
+ (void)fprintf(stderr, "Modified %s",
+ cdf_ctime(&ts.tv_sec, buf));
+ (void)fprintf(stderr, "Stream %d\n", d->d_stream_first_sector);
+ (void)fprintf(stderr, "Size %d\n", d->d_size);
+ switch (d->d_type) {
+ case CDF_DIR_TYPE_USER_STORAGE:
+ (void)fprintf(stderr, "Storage: %d\n", d->d_storage);
+ break;
+ case CDF_DIR_TYPE_USER_STREAM:
+ if (sst == NULL)
+ break;
+ if (cdf_read_sector_chain(info, h, sat, ssat, sst,
+ d->d_stream_first_sector, d->d_size, &scn) == -1) {
+ warn("Can't read stream for %s at %d len %d",
+ name, d->d_stream_first_sector, d->d_size);
+ break;
+ }
+ cdf_dump_stream(&scn);
+ free(scn.sst_tab);
+ break;
+ default:
+ break;
+ }
+
+ }
+}
+
+void
+cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
+{
+ cdf_timestamp_t tp;
+ struct timespec ts;
+ char buf[64];
+ size_t i, j;
+
+ for (i = 0; i < count; i++) {
+ cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
+ (void)fprintf(stderr, "%" SIZE_T_FORMAT "u) %s: ", i, buf);
+ switch (info[i].pi_type) {
+ case CDF_NULL:
+ break;
+ case CDF_SIGNED16:
+ (void)fprintf(stderr, "signed 16 [%hd]\n",
+ info[i].pi_s16);
+ break;
+ case CDF_SIGNED32:
+ (void)fprintf(stderr, "signed 32 [%d]\n",
+ info[i].pi_s32);
+ break;
+ case CDF_UNSIGNED32:
+ (void)fprintf(stderr, "unsigned 32 [%u]\n",
+ info[i].pi_u32);
+ break;
+ case CDF_FLOAT:
+ (void)fprintf(stderr, "float [%g]\n",
+ info[i].pi_f);
+ break;
+ case CDF_DOUBLE:
+ (void)fprintf(stderr, "double [%g]\n",
+ info[i].pi_d);
+ break;
+ case CDF_LENGTH32_STRING:
+ (void)fprintf(stderr, "string %u [%.*s]\n",
+ info[i].pi_str.s_len,
+ info[i].pi_str.s_len, info[i].pi_str.s_buf);
+ break;
+ case CDF_LENGTH32_WSTRING:
+ (void)fprintf(stderr, "string %u [",
+ info[i].pi_str.s_len);
+ for (j = 0; j < info[i].pi_str.s_len - 1; j++)
+ (void)fputc(info[i].pi_str.s_buf[j << 1], stderr);
+ (void)fprintf(stderr, "]\n");
+ break;
+ case CDF_FILETIME:
+ tp = info[i].pi_tp;
+ if (tp < 1000000000000000LL) {
+ cdf_print_elapsed_time(buf, sizeof(buf), tp);
+ (void)fprintf(stderr, "timestamp %s\n", buf);
+ } else {
+ char tbuf[26];
+ cdf_timestamp_to_timespec(&ts, tp);
+ (void)fprintf(stderr, "timestamp %s",
+ cdf_ctime(&ts.tv_sec, tbuf));
+ }
+ break;
+ case CDF_CLIPBOARD:
+ (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32);
+ break;
+ default:
+ DPRINTF(("Don't know how to deal with %#x\n",
+ info[i].pi_type));
+ break;
+ }
+ }
+}
+
+
+void
+cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst)
+{
+ char buf[128];
+ cdf_summary_info_header_t ssi;
+ cdf_property_info_t *info;
+ size_t count;
+
+ (void)&h;
+ if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1)
+ return;
+ (void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order);
+ (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff,
+ ssi.si_os_version >> 8);
+ (void)fprintf(stderr, "Os %d\n", ssi.si_os);
+ cdf_print_classid(buf, sizeof(buf), &ssi.si_class);
+ (void)fprintf(stderr, "Class %s\n", buf);
+ (void)fprintf(stderr, "Count %d\n", ssi.si_count);
+ cdf_dump_property_info(info, count);
+ free(info);
+}
+
+
+void
+cdf_dump_catalog(const cdf_header_t *h, const cdf_stream_t *sst)
+{
+ cdf_catalog_t *cat;
+ cdf_unpack_catalog(h, sst, &cat);
+ const cdf_catalog_entry_t *ce = cat->cat_e;
+ struct timespec ts;
+ char tbuf[64], sbuf[256];
+ size_t i;
+
+ printf("Catalog:\n");
+ for (i = 0; i < cat->cat_num; i++) {
+ cdf_timestamp_to_timespec(&ts, ce[i].ce_timestamp);
+ printf("\t%d %s %s", ce[i].ce_num,
+ cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name),
+ cdf_ctime(&ts.tv_sec, tbuf));
+ }
+ free(cat);
+}
+
+#endif
+
+#ifdef TEST
+int
+main(int argc, char *argv[])
+{
+ int i;
+ cdf_header_t h;
+ cdf_sat_t sat, ssat;
+ cdf_stream_t sst, scn;
+ cdf_dir_t dir;
+ cdf_info_t info;
+ const cdf_directory_t *root;
+#ifdef __linux__
+#define getprogname() __progname
+ extern char *__progname;
+#endif
+ if (argc < 2) {
+ (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname());
+ return -1;
+ }
+
+ info.i_buf = NULL;
+ info.i_len = 0;
+ for (i = 1; i < argc; i++) {
+ if ((info.i_fd = open(argv[1], O_RDONLY)) == -1)
+ err(1, "Cannot open `%s'", argv[1]);
+
+ if (cdf_read_header(&info, &h) == -1)
+ err(1, "Cannot read header");
+#ifdef CDF_DEBUG
+ cdf_dump_header(&h);
+#endif
+
+ if (cdf_read_sat(&info, &h, &sat) == -1)
+ err(1, "Cannot read sat");
+#ifdef CDF_DEBUG
+ cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
+#endif
+
+ if (cdf_read_ssat(&info, &h, &sat, &ssat) == -1)
+ err(1, "Cannot read ssat");
+#ifdef CDF_DEBUG
+ cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
+#endif
+
+ if (cdf_read_dir(&info, &h, &sat, &dir) == -1)
+ err(1, "Cannot read dir");
+
+ if (cdf_read_short_stream(&info, &h, &sat, &dir, &sst, &root)
+ == -1)
+ err(1, "Cannot read short stream");
+#ifdef CDF_DEBUG
+ cdf_dump_stream(&sst);
+#endif
+
+#ifdef CDF_DEBUG
+ cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
+#endif
+
+
+ if (cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
+ &scn) == -1)
+ warn("Cannot read summary info");
+#ifdef CDF_DEBUG
+ else
+ cdf_dump_summary_info(&h, &scn);
+#endif
+ if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst,
+ &dir, "Catalog", &scn) == -1)
+ warn("Cannot read catalog");
+#ifdef CDF_DEBUG
+ else
+ cdf_dump_catalog(&h, &scn);
+#endif
+
+ (void)close(info.i_fd);
+ }
+
+ return 0;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/cdf.h b/node_modules/mmmagic/deps/libmagic/src/cdf.h
new file mode 100644
index 0000000..f2df830
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/cdf.h
@@ -0,0 +1,352 @@
+/*-
+ * Copyright (c) 2008 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Parse Composite Document Files, the format used in Microsoft Office
+ * document files before they switched to zipped XML.
+ * Info from: http://sc.openoffice.org/compdocfileformat.pdf
+ *
+ * N.B. This is the "Composite Document File" format, and not the
+ * "Compound Document Format", nor the "Channel Definition Format".
+ */
+
+#ifndef _H_CDF_
+#define _H_CDF_
+
+#ifdef WIN32
+#include <winsock2.h>
+#define timespec timeval
+#define tv_nsec tv_usec
+#endif
+#ifdef __DJGPP__
+#define timespec timeval
+#define tv_nsec tv_usec
+#endif
+
+typedef int32_t cdf_secid_t;
+
+#define CDF_LOOP_LIMIT 10000
+
+#define CDF_SECID_NULL 0
+#define CDF_SECID_FREE -1
+#define CDF_SECID_END_OF_CHAIN -2
+#define CDF_SECID_SECTOR_ALLOCATION_TABLE -3
+#define CDF_SECID_MASTER_SECTOR_ALLOCATION_TABLE -4
+
+typedef struct {
+ uint64_t h_magic;
+#define CDF_MAGIC 0xE11AB1A1E011CFD0LL
+ uint64_t h_uuid[2];
+ uint16_t h_revision;
+ uint16_t h_version;
+ uint16_t h_byte_order;
+ uint16_t h_sec_size_p2;
+ uint16_t h_short_sec_size_p2;
+ uint8_t h_unused0[10];
+ uint32_t h_num_sectors_in_sat;
+ uint32_t h_secid_first_directory;
+ uint8_t h_unused1[4];
+ uint32_t h_min_size_standard_stream;
+ cdf_secid_t h_secid_first_sector_in_short_sat;
+ uint32_t h_num_sectors_in_short_sat;
+ cdf_secid_t h_secid_first_sector_in_master_sat;
+ uint32_t h_num_sectors_in_master_sat;
+ cdf_secid_t h_master_sat[436/4];
+} cdf_header_t;
+
+#define CDF_SEC_SIZE(h) ((size_t)(1 << (h)->h_sec_size_p2))
+#define CDF_SEC_POS(h, secid) (CDF_SEC_SIZE(h) + (secid) * CDF_SEC_SIZE(h))
+#define CDF_SHORT_SEC_SIZE(h) ((size_t)(1 << (h)->h_short_sec_size_p2))
+#define CDF_SHORT_SEC_POS(h, secid) ((secid) * CDF_SHORT_SEC_SIZE(h))
+
+typedef int32_t cdf_dirid_t;
+#define CDF_DIRID_NULL -1
+
+typedef int64_t cdf_timestamp_t;
+#define CDF_BASE_YEAR 1601
+#define CDF_TIME_PREC 10000000
+
+typedef struct {
+ uint16_t d_name[32];
+ uint16_t d_namelen;
+ uint8_t d_type;
+#define CDF_DIR_TYPE_EMPTY 0
+#define CDF_DIR_TYPE_USER_STORAGE 1
+#define CDF_DIR_TYPE_USER_STREAM 2
+#define CDF_DIR_TYPE_LOCKBYTES 3
+#define CDF_DIR_TYPE_PROPERTY 4
+#define CDF_DIR_TYPE_ROOT_STORAGE 5
+ uint8_t d_color;
+#define CDF_DIR_COLOR_READ 0
+#define CDF_DIR_COLOR_BLACK 1
+ cdf_dirid_t d_left_child;
+ cdf_dirid_t d_right_child;
+ cdf_dirid_t d_storage;
+ uint64_t d_storage_uuid[2];
+ uint32_t d_flags;
+ cdf_timestamp_t d_created;
+ cdf_timestamp_t d_modified;
+ cdf_secid_t d_stream_first_sector;
+ uint32_t d_size;
+ uint32_t d_unused0;
+} cdf_directory_t;
+
+#define CDF_DIRECTORY_SIZE 128
+
+typedef struct {
+ cdf_secid_t *sat_tab;
+ size_t sat_len;
+} cdf_sat_t;
+
+typedef struct {
+ cdf_directory_t *dir_tab;
+ size_t dir_len;
+} cdf_dir_t;
+
+typedef struct {
+ void *sst_tab;
+ size_t sst_len; /* Number of sectors */
+ size_t sst_dirlen; /* Directory sector size */
+ size_t sst_ss; /* Sector size */
+} cdf_stream_t;
+
+typedef struct {
+ uint32_t cl_dword;
+ uint16_t cl_word[2];
+ uint8_t cl_two[2];
+ uint8_t cl_six[6];
+} cdf_classid_t;
+
+typedef struct {
+ uint16_t si_byte_order;
+ uint16_t si_zero;
+ uint16_t si_os_version;
+ uint16_t si_os;
+ cdf_classid_t si_class;
+ uint32_t si_count;
+} cdf_summary_info_header_t;
+
+#define CDF_SECTION_DECLARATION_OFFSET 0x1c
+
+typedef struct {
+ cdf_classid_t sd_class;
+ uint32_t sd_offset;
+} cdf_section_declaration_t;
+
+typedef struct {
+ uint32_t sh_len;
+ uint32_t sh_properties;
+} cdf_section_header_t;
+
+typedef struct {
+ uint32_t pi_id;
+ uint32_t pi_type;
+ union {
+ uint16_t _pi_u16;
+ int16_t _pi_s16;
+ uint32_t _pi_u32;
+ int32_t _pi_s32;
+ uint64_t _pi_u64;
+ int64_t _pi_s64;
+ cdf_timestamp_t _pi_tp;
+ float _pi_f;
+ double _pi_d;
+ struct {
+ uint32_t s_len;
+ const char *s_buf;
+ } _pi_str;
+ } pi_val;
+#define pi_u64 pi_val._pi_u64
+#define pi_s64 pi_val._pi_s64
+#define pi_u32 pi_val._pi_u32
+#define pi_s32 pi_val._pi_s32
+#define pi_u16 pi_val._pi_u16
+#define pi_s16 pi_val._pi_s16
+#define pi_f pi_val._pi_f
+#define pi_d pi_val._pi_d
+#define pi_tp pi_val._pi_tp
+#define pi_str pi_val._pi_str
+} cdf_property_info_t;
+
+#define CDF_ROUND(val, by) (((val) + (by) - 1) & ~((by) - 1))
+
+/* Variant type definitions */
+#define CDF_EMPTY 0x00000000
+#define CDF_NULL 0x00000001
+#define CDF_SIGNED16 0x00000002
+#define CDF_SIGNED32 0x00000003
+#define CDF_FLOAT 0x00000004
+#define CDF_DOUBLE 0x00000005
+#define CDF_CY 0x00000006
+#define CDF_DATE 0x00000007
+#define CDF_BSTR 0x00000008
+#define CDF_DISPATCH 0x00000009
+#define CDF_ERROR 0x0000000a
+#define CDF_BOOL 0x0000000b
+#define CDF_VARIANT 0x0000000c
+#define CDF_UNKNOWN 0x0000000d
+#define CDF_DECIMAL 0x0000000e
+#define CDF_SIGNED8 0x00000010
+#define CDF_UNSIGNED8 0x00000011
+#define CDF_UNSIGNED16 0x00000012
+#define CDF_UNSIGNED32 0x00000013
+#define CDF_SIGNED64 0x00000014
+#define CDF_UNSIGNED64 0x00000015
+#define CDF_INT 0x00000016
+#define CDF_UINT 0x00000017
+#define CDF_VOID 0x00000018
+#define CDF_HRESULT 0x00000019
+#define CDF_PTR 0x0000001a
+#define CDF_SAFEARRAY 0x0000001b
+#define CDF_CARRAY 0x0000001c
+#define CDF_USERDEFINED 0x0000001d
+#define CDF_LENGTH32_STRING 0x0000001e
+#define CDF_LENGTH32_WSTRING 0x0000001f
+#define CDF_FILETIME 0x00000040
+#define CDF_BLOB 0x00000041
+#define CDF_STREAM 0x00000042
+#define CDF_STORAGE 0x00000043
+#define CDF_STREAMED_OBJECT 0x00000044
+#define CDF_STORED_OBJECT 0x00000045
+#define CDF_BLOB_OBJECT 0x00000046
+#define CDF_CLIPBOARD 0x00000047
+#define CDF_CLSID 0x00000048
+#define CDF_VECTOR 0x00001000
+#define CDF_ARRAY 0x00002000
+#define CDF_BYREF 0x00004000
+#define CDF_RESERVED 0x00008000
+#define CDF_ILLEGAL 0x0000ffff
+#define CDF_ILLEGALMASKED 0x00000fff
+#define CDF_TYPEMASK 0x00000fff
+
+#define CDF_PROPERTY_CODE_PAGE 0x00000001
+#define CDF_PROPERTY_TITLE 0x00000002
+#define CDF_PROPERTY_SUBJECT 0x00000003
+#define CDF_PROPERTY_AUTHOR 0x00000004
+#define CDF_PROPERTY_KEYWORDS 0x00000005
+#define CDF_PROPERTY_COMMENTS 0x00000006
+#define CDF_PROPERTY_TEMPLATE 0x00000007
+#define CDF_PROPERTY_LAST_SAVED_BY 0x00000008
+#define CDF_PROPERTY_REVISION_NUMBER 0x00000009
+#define CDF_PROPERTY_TOTAL_EDITING_TIME 0x0000000a
+#define CDF_PROPERTY_LAST_PRINTED 0X0000000b
+#define CDF_PROPERTY_CREATE_TIME 0x0000000c
+#define CDF_PROPERTY_LAST_SAVED_TIME 0x0000000d
+#define CDF_PROPERTY_NUMBER_OF_PAGES 0x0000000e
+#define CDF_PROPERTY_NUMBER_OF_WORDS 0x0000000f
+#define CDF_PROPERTY_NUMBER_OF_CHARACTERS 0x00000010
+#define CDF_PROPERTY_THUMBNAIL 0x00000011
+#define CDF_PROPERTY_NAME_OF_APPLICATION 0x00000012
+#define CDF_PROPERTY_SECURITY 0x00000013
+#define CDF_PROPERTY_LOCALE_ID 0x80000000
+
+typedef struct {
+ int i_fd;
+ const unsigned char *i_buf;
+ size_t i_len;
+} cdf_info_t;
+
+
+typedef struct {
+ uint16_t ce_namlen;
+ uint32_t ce_num;
+ uint64_t ce_timestamp;
+ uint16_t ce_name[256];
+} cdf_catalog_entry_t;
+
+typedef struct {
+ size_t cat_num;
+ cdf_catalog_entry_t cat_e[1];
+} cdf_catalog_t;
+
+struct timespec;
+int cdf_timestamp_to_timespec(struct timespec *, cdf_timestamp_t);
+int cdf_timespec_to_timestamp(cdf_timestamp_t *, const struct timespec *);
+int cdf_read_header(const cdf_info_t *, cdf_header_t *);
+void cdf_swap_header(cdf_header_t *);
+void cdf_unpack_header(cdf_header_t *, char *);
+void cdf_swap_dir(cdf_directory_t *);
+void cdf_unpack_dir(cdf_directory_t *, char *);
+void cdf_swap_class(cdf_classid_t *);
+ssize_t cdf_read_sector(const cdf_info_t *, void *, size_t, size_t,
+ const cdf_header_t *, cdf_secid_t);
+ssize_t cdf_read_short_sector(const cdf_stream_t *, void *, size_t, size_t,
+ const cdf_header_t *, cdf_secid_t);
+int cdf_read_sat(const cdf_info_t *, cdf_header_t *, cdf_sat_t *);
+size_t cdf_count_chain(const cdf_sat_t *, cdf_secid_t, size_t);
+int cdf_read_long_sector_chain(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, cdf_secid_t, size_t, cdf_stream_t *);
+int cdf_read_short_sector_chain(const cdf_header_t *, const cdf_sat_t *,
+ const cdf_stream_t *, cdf_secid_t, size_t, cdf_stream_t *);
+int cdf_read_sector_chain(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *, cdf_secid_t,
+ size_t, cdf_stream_t *);
+int cdf_read_dir(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *,
+ cdf_dir_t *);
+int cdf_read_ssat(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *,
+ cdf_sat_t *);
+int cdf_read_short_stream(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_dir_t *, cdf_stream_t *,
+ const cdf_directory_t **);
+int cdf_read_property_info(const cdf_stream_t *, const cdf_header_t *, uint32_t,
+ cdf_property_info_t **, size_t *, size_t *);
+int cdf_read_user_stream(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
+ const cdf_dir_t *, const char *, cdf_stream_t *);
+int cdf_find_stream(const cdf_dir_t *, const char *, int);
+int cdf_zero_stream(cdf_stream_t *);
+int cdf_read_doc_summary_info(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
+ const cdf_dir_t *, cdf_stream_t *);
+int cdf_read_summary_info(const cdf_info_t *, const cdf_header_t *,
+ const cdf_sat_t *, const cdf_sat_t *, const cdf_stream_t *,
+ const cdf_dir_t *, cdf_stream_t *);
+int cdf_unpack_summary_info(const cdf_stream_t *, const cdf_header_t *,
+ cdf_summary_info_header_t *, cdf_property_info_t **, size_t *);
+int cdf_unpack_catalog(const cdf_header_t *, const cdf_stream_t *,
+ cdf_catalog_t **);
+int cdf_print_classid(char *, size_t, const cdf_classid_t *);
+int cdf_print_property_name(char *, size_t, uint32_t);
+int cdf_print_elapsed_time(char *, size_t, cdf_timestamp_t);
+uint16_t cdf_tole2(uint16_t);
+uint32_t cdf_tole4(uint32_t);
+uint64_t cdf_tole8(uint64_t);
+char *cdf_ctime(const time_t *, char *);
+char *cdf_u16tos8(char *, size_t, const uint16_t *);
+
+#ifdef CDF_DEBUG
+void cdf_dump_header(const cdf_header_t *);
+void cdf_dump_sat(const char *, const cdf_sat_t *, size_t);
+void cdf_dump(const void *, size_t);
+void cdf_dump_stream(const cdf_stream_t *);
+void cdf_dump_dir(const cdf_info_t *, const cdf_header_t *, const cdf_sat_t *,
+ const cdf_sat_t *, const cdf_stream_t *, const cdf_dir_t *);
+void cdf_dump_property_info(const cdf_property_info_t *, size_t);
+void cdf_dump_summary_info(const cdf_header_t *, const cdf_stream_t *);
+void cdf_dump_catalog(const cdf_header_t *, const cdf_stream_t *);
+#endif
+
+
+#endif /* _H_CDF_ */
diff --git a/node_modules/mmmagic/deps/libmagic/src/cdf_time.c b/node_modules/mmmagic/deps/libmagic/src/cdf_time.c
new file mode 100644
index 0000000..2bdcd2a
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/cdf_time.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2008 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: cdf_time.c,v 1.16 2017/03/29 15:57:48 christos Exp $")
+#endif
+
+#include <time.h>
+#ifdef TEST
+#include <err.h>
+#endif
+#include <string.h>
+
+#include "cdf.h"
+
+#define isleap(y) ((((y) % 4) == 0) && \
+ ((((y) % 100) != 0) || (((y) % 400) == 0)))
+
+static const int mdays[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * Return the number of days between jan 01 1601 and jan 01 of year.
+ */
+static int
+cdf_getdays(int year)
+{
+ int days = 0;
+ int y;
+
+ for (y = CDF_BASE_YEAR; y < year; y++)
+ days += isleap(y) + 365;
+
+ return days;
+}
+
+/*
+ * Return the day within the month
+ */
+static int
+cdf_getday(int year, int days)
+{
+ size_t m;
+
+ for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) {
+ int sub = mdays[m] + (m == 1 && isleap(year));
+ if (days < sub)
+ return days;
+ days -= sub;
+ }
+ return days;
+}
+
+/*
+ * Return the 0...11 month number.
+ */
+static int
+cdf_getmonth(int year, int days)
+{
+ size_t m;
+
+ for (m = 0; m < sizeof(mdays) / sizeof(mdays[0]); m++) {
+ days -= mdays[m];
+ if (m == 1 && isleap(year))
+ days--;
+ if (days <= 0)
+ return (int)m;
+ }
+ return (int)m;
+}
+
+int
+cdf_timestamp_to_timespec(struct timespec *ts, cdf_timestamp_t t)
+{
+ struct tm tm;
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+ static char UTC[] = "UTC";
+#endif
+ int rdays;
+
+ /* Unit is 100's of nanoseconds */
+ ts->tv_nsec = (t % CDF_TIME_PREC) * 100;
+
+ t /= CDF_TIME_PREC;
+ tm.tm_sec = (int)(t % 60);
+ t /= 60;
+
+ tm.tm_min = (int)(t % 60);
+ t /= 60;
+
+ tm.tm_hour = (int)(t % 24);
+ t /= 24;
+
+ /* XXX: Approx */
+ tm.tm_year = (int)(CDF_BASE_YEAR + (t / 365));
+
+ rdays = cdf_getdays(tm.tm_year);
+ t -= rdays - 1;
+ tm.tm_mday = cdf_getday(tm.tm_year, (int)t);
+ tm.tm_mon = cdf_getmonth(tm.tm_year, (int)t);
+ tm.tm_wday = 0;
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+#ifdef HAVE_STRUCT_TM_TM_GMTOFF
+ tm.tm_gmtoff = 0;
+#endif
+#ifdef HAVE_STRUCT_TM_TM_ZONE
+ tm.tm_zone = UTC;
+#endif
+ tm.tm_year -= 1900;
+ ts->tv_sec = mktime(&tm);
+ if (ts->tv_sec == -1) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int
+/*ARGSUSED*/
+cdf_timespec_to_timestamp(cdf_timestamp_t *t, const struct timespec *ts)
+{
+#ifndef __lint__
+ (void)&t;
+ (void)&ts;
+#endif
+#ifdef notyet
+ struct tm tm;
+ if (gmtime_r(&ts->ts_sec, &tm) == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ *t = (ts->ts_nsec / 100) * CDF_TIME_PREC;
+ *t = tm.tm_sec;
+ *t += tm.tm_min * 60;
+ *t += tm.tm_hour * 60 * 60;
+ *t += tm.tm_mday * 60 * 60 * 24;
+#endif
+ return 0;
+}
+
+char *
+cdf_ctime(const time_t *sec, char *buf)
+{
+ char *ptr = ctime_r(sec, buf);
+ if (ptr != NULL)
+ return buf;
+ (void)snprintf(buf, 26, "*Bad* %#16.16" INT64_T_FORMAT "x\n",
+ (long long)*sec);
+ return buf;
+}
+
+
+#ifdef TEST_TIME
+int
+main(int argc, char *argv[])
+{
+ struct timespec ts;
+ char buf[25];
+ static const cdf_timestamp_t tst = 0x01A5E403C2D59C00ULL;
+ static const char *ref = "Sat Apr 23 01:30:00 1977";
+ char *p, *q;
+
+ cdf_timestamp_to_timespec(&ts, tst);
+ p = cdf_ctime(&ts.tv_sec, buf);
+ if ((q = strchr(p, '\n')) != NULL)
+ *q = '\0';
+ if (strcmp(ref, p) != 0)
+ errx(1, "Error date %s != %s\n", ref, p);
+ return 0;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/compress.c b/node_modules/mmmagic/deps/libmagic/src/compress.c
new file mode 100644
index 0000000..2f789cd
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/compress.c
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * compress routines:
+ * zmagic() - returns 0 if not recognized, uncompresses and prints
+ * information if recognized
+ * uncompress(method, old, n, newch) - uncompress old into new,
+ * using method, return sizeof new
+ */
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: compress.c,v 1.105 2017/05/25 00:13:03 christos Exp $")
+#endif
+
+#include "magic.h"
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+# ifndef HAVE_SIG_T
+typedef void (*sig_t)(int);
+# endif /* HAVE_SIG_T */
+#endif
+#if !defined(__MINGW32__) && !defined(WIN32)
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#if defined(HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#endif
+#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT)
+#define BUILTIN_DECOMPRESS
+#include <zlib.h>
+#endif
+#ifdef DEBUG
+int tty = -1;
+#define DPRINTF(...) do { \
+ if (tty == -1) \
+ tty = open("/dev/tty", O_RDWR); \
+ if (tty == -1) \
+ abort(); \
+ dprintf(tty, __VA_ARGS__); \
+} while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(...)
+#endif
+
+#ifdef ZLIBSUPPORT
+/*
+ * The following python code is not really used because ZLIBSUPPORT is only
+ * defined if we have a built-in zlib, and the built-in zlib handles that.
+ * That is not true for android where we have zlib.h and not -lz.
+ */
+static const char zlibcode[] =
+ "import sys, zlib; sys.stdout.write(zlib.decompress(sys.stdin.read()))";
+
+static const char *zlib_args[] = { "python", "-c", zlibcode, NULL };
+
+static int
+zlibcmp(const unsigned char *buf)
+{
+ unsigned short x = 1;
+ unsigned char *s = CAST(unsigned char *, CAST(void *, &x));
+
+ if ((buf[0] & 0xf) != 8 || (buf[0] & 0x80) != 0)
+ return 0;
+ if (s[0] != 1) /* endianness test */
+ x = buf[0] | (buf[1] << 8);
+ else
+ x = buf[1] | (buf[0] << 8);
+ if (x % 31)
+ return 0;
+ return 1;
+}
+#endif
+
+#define gzip_flags "-cd"
+#define lrzip_flags "-do"
+#define lzip_flags gzip_flags
+
+static const char *gzip_args[] = {
+ "gzip", gzip_flags, NULL
+};
+static const char *uncompress_args[] = {
+ "uncompress", "-c", NULL
+};
+static const char *bzip2_args[] = {
+ "bzip2", "-cd", NULL
+};
+static const char *lzip_args[] = {
+ "lzip", lzip_flags, NULL
+};
+static const char *xz_args[] = {
+ "xz", "-cd", NULL
+};
+static const char *lrzip_args[] = {
+ "lrzip", lrzip_flags, NULL
+};
+static const char *lz4_args[] = {
+ "lz4", "-cd", NULL
+};
+static const char *zstd_args[] = {
+ "zstd", "-cd", NULL
+};
+
+private const struct {
+ const void *magic;
+ size_t maglen;
+ const char **argv;
+} compr[] = {
+ { "\037\235", 2, gzip_args }, /* compressed */
+ /* Uncompress can get stuck; so use gzip first if we have it
+ * Idea from Damien Clark, thanks! */
+ { "\037\235", 2, uncompress_args }, /* compressed */
+ { "\037\213", 2, gzip_args }, /* gzipped */
+ { "\037\236", 2, gzip_args }, /* frozen */
+ { "\037\240", 2, gzip_args }, /* SCO LZH */
+ /* the standard pack utilities do not accept standard input */
+ { "\037\036", 2, gzip_args }, /* packed */
+ { "PK\3\4", 4, gzip_args }, /* pkzipped, */
+ /* ...only first file examined */
+ { "BZh", 3, bzip2_args }, /* bzip2-ed */
+ { "LZIP", 4, lzip_args }, /* lzip-ed */
+ { "\3757zXZ\0", 6, xz_args }, /* XZ Utils */
+ { "LRZI", 4, lrzip_args }, /* LRZIP */
+ { "\004\"M\030",4, lz4_args }, /* LZ4 */
+ { "\x28\xB5\x2F\xFD", 4, zstd_args }, /* zstd */
+#ifdef ZLIBSUPPORT
+ { RCAST(const void *, zlibcmp), 0, zlib_args }, /* zlib */
+#endif
+};
+
+#define OKDATA 0
+#define NODATA 1
+#define ERRDATA 2
+
+private ssize_t swrite(int, const void *, size_t);
+#if HAVE_FORK
+private size_t ncompr = sizeof(compr) / sizeof(compr[0]);
+private int uncompressbuf(int, size_t, size_t, const unsigned char *,
+ unsigned char **, size_t *);
+#ifdef BUILTIN_DECOMPRESS
+private int uncompresszlib(const unsigned char *, unsigned char **, size_t,
+ size_t *, int);
+private int uncompressgzipped(const unsigned char *, unsigned char **, size_t,
+ size_t *);
+#endif
+static int makeerror(unsigned char **, size_t *, const char *, ...)
+ __attribute__((__format__(__printf__, 3, 4)));
+private const char *methodname(size_t);
+
+protected int
+file_zmagic(struct magic_set *ms, int fd, const char *name,
+ const unsigned char *buf, size_t nbytes)
+{
+ unsigned char *newbuf = NULL;
+ size_t i, nsz;
+ char *rbuf;
+ file_pushbuf_t *pb;
+ int urv, prv, rv = 0;
+ int mime = ms->flags & MAGIC_MIME;
+#ifdef HAVE_SIGNAL_H
+ sig_t osigpipe;
+#endif
+
+ if ((ms->flags & MAGIC_COMPRESS) == 0)
+ return 0;
+
+#ifdef HAVE_SIGNAL_H
+ osigpipe = signal(SIGPIPE, SIG_IGN);
+#endif
+ for (i = 0; i < ncompr; i++) {
+ int zm;
+ if (nbytes < compr[i].maglen)
+ continue;
+#ifdef ZLIBSUPPORT
+ if (compr[i].maglen == 0)
+ zm = (RCAST(int (*)(const unsigned char *),
+ CCAST(void *, compr[i].magic)))(buf);
+ else
+#endif
+ zm = memcmp(buf, compr[i].magic, compr[i].maglen) == 0;
+
+ if (!zm)
+ continue;
+ nsz = nbytes;
+ urv = uncompressbuf(fd, ms->bytes_max, i, buf, &newbuf, &nsz);
+ DPRINTF("uncompressbuf = %d, %s, %zu\n", urv, (char *)newbuf,
+ nsz);
+ switch (urv) {
+ case OKDATA:
+ case ERRDATA:
+
+ ms->flags &= ~MAGIC_COMPRESS;
+ if (urv == ERRDATA)
+ prv = file_printf(ms, "%s ERROR: %s",
+ methodname(i), newbuf);
+ else
+ prv = file_buffer(ms, -1, name, newbuf, nsz);
+ if (prv == -1)
+ goto error;
+ rv = 1;
+ if ((ms->flags & MAGIC_COMPRESS_TRANSP) != 0)
+ goto out;
+ if (mime != MAGIC_MIME && mime != 0)
+ goto out;
+ if ((file_printf(ms,
+ mime ? " compressed-encoding=" : " (")) == -1)
+ goto error;
+ if ((pb = file_push_buffer(ms)) == NULL)
+ goto error;
+ /*
+ * XXX: If file_buffer fails here, we overwrite
+ * the compressed text. FIXME.
+ */
+ if (file_buffer(ms, -1, NULL, buf, nbytes) == -1)
+ goto error;
+ if ((rbuf = file_pop_buffer(ms, pb)) != NULL) {
+ if (file_printf(ms, "%s", rbuf) == -1) {
+ free(rbuf);
+ goto error;
+ }
+ free(rbuf);
+ }
+ if (!mime && file_printf(ms, ")") == -1)
+ goto error;
+ /*FALLTHROUGH*/
+ case NODATA:
+ break;
+ default:
+ abort();
+ /*NOTREACHED*/
+ error:
+ rv = -1;
+ break;
+ }
+ }
+out:
+ DPRINTF("rv = %d\n", rv);
+
+#ifdef HAVE_SIGNAL_H
+ (void)signal(SIGPIPE, osigpipe);
+#endif
+ free(newbuf);
+ ms->flags |= MAGIC_COMPRESS;
+ DPRINTF("Zmagic returns %d\n", rv);
+ return rv;
+}
+#endif
+/*
+ * `safe' write for sockets and pipes.
+ */
+private ssize_t
+swrite(int fd, const void *buf, size_t n)
+{
+ ssize_t rv;
+ size_t rn = n;
+
+ do
+ switch (rv = write(fd, buf, n)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ return -1;
+ default:
+ n -= rv;
+ buf = CAST(const char *, buf) + rv;
+ break;
+ }
+ while (n > 0);
+ return rn;
+}
+
+
+/*
+ * `safe' read for sockets and pipes.
+ */
+protected ssize_t
+sread(int fd, void *buf, size_t n, int canbepipe __attribute__((__unused__)))
+{
+ ssize_t rv;
+#ifdef FIONREAD
+ int t = 0;
+#endif
+ size_t rn = n;
+
+ if (fd == STDIN_FILENO)
+ goto nocheck;
+
+#ifdef FIONREAD
+ if (canbepipe && (ioctl(fd, FIONREAD, &t) == -1 || t == 0)) {
+#ifdef FD_ZERO
+ ssize_t cnt;
+ for (cnt = 0;; cnt++) {
+ fd_set check;
+ struct timeval tout = {0, 100 * 1000};
+ int selrv;
+
+ FD_ZERO(&check);
+ FD_SET(fd, &check);
+
+ /*
+ * Avoid soft deadlock: do not read if there
+ * is nothing to read from sockets and pipes.
+ */
+ selrv = select(fd + 1, &check, NULL, NULL, &tout);
+ if (selrv == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ } else if (selrv == 0 && cnt >= 5) {
+ return 0;
+ } else
+ break;
+ }
+#endif
+ (void)ioctl(fd, FIONREAD, &t);
+ }
+
+ if (t > 0 && (size_t)t < n) {
+ n = t;
+ rn = n;
+ }
+#endif
+
+nocheck:
+ do
+ switch ((rv = read(fd, buf, n))) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ return -1;
+ case 0:
+ return rn - n;
+ default:
+ n -= rv;
+ buf = CAST(char *, CCAST(void *, buf)) + rv;
+ break;
+ }
+ while (n > 0);
+ return rn;
+}
+
+protected int
+file_pipe2file(struct magic_set *ms, int fd, const void *startbuf,
+ size_t nbytes)
+{
+ char buf[4096];
+ ssize_t r;
+ int tfd;
+
+ (void)strlcpy(buf, "/tmp/file.XXXXXX", sizeof buf);
+#ifndef HAVE_MKSTEMP
+ {
+ char *ptr = mktemp(buf);
+ tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
+ r = errno;
+ (void)unlink(ptr);
+ errno = r;
+ }
+#else
+ {
+ int te;
+ tfd = mkstemp(buf);
+ te = errno;
+ (void)unlink(buf);
+ errno = te;
+ }
+#endif
+ if (tfd == -1) {
+ file_error(ms, errno,
+ "cannot create temporary file for pipe copy");
+ return -1;
+ }
+
+ if (swrite(tfd, startbuf, nbytes) != (ssize_t)nbytes)
+ r = 1;
+ else {
+ while ((r = sread(fd, buf, sizeof(buf), 1)) > 0)
+ if (swrite(tfd, buf, (size_t)r) != r)
+ break;
+ }
+
+ switch (r) {
+ case -1:
+ file_error(ms, errno, "error copying from pipe to temp file");
+ return -1;
+ case 0:
+ break;
+ default:
+ file_error(ms, errno, "error while writing to temp file");
+ return -1;
+ }
+
+ /*
+ * We duplicate the file descriptor, because fclose on a
+ * tmpfile will delete the file, but any open descriptors
+ * can still access the phantom inode.
+ */
+ if ((fd = dup2(tfd, fd)) == -1) {
+ file_error(ms, errno, "could not dup descriptor for temp file");
+ return -1;
+ }
+ (void)close(tfd);
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ file_badseek(ms);
+ return -1;
+ }
+ return fd;
+}
+#if HAVE_FORK
+#ifdef BUILTIN_DECOMPRESS
+
+#define FHCRC (1 << 1)
+#define FEXTRA (1 << 2)
+#define FNAME (1 << 3)
+#define FCOMMENT (1 << 4)
+
+
+private int
+uncompressgzipped(const unsigned char *old, unsigned char **newch,
+ size_t bytes_max, size_t *n)
+{
+ unsigned char flg = old[3];
+ size_t data_start = 10;
+
+ if (flg & FEXTRA) {
+ if (data_start + 1 >= *n)
+ goto err;
+ data_start += 2 + old[data_start] + old[data_start + 1] * 256;
+ }
+ if (flg & FNAME) {
+ while(data_start < *n && old[data_start])
+ data_start++;
+ data_start++;
+ }
+ if (flg & FCOMMENT) {
+ while(data_start < *n && old[data_start])
+ data_start++;
+ data_start++;
+ }
+ if (flg & FHCRC)
+ data_start += 2;
+
+ if (data_start >= *n)
+ goto err;
+
+ *n -= data_start;
+ old += data_start;
+ return uncompresszlib(old, newch, bytes_max, n, 0);
+err:
+ return makeerror(newch, n, "File too short");
+}
+
+private int
+uncompresszlib(const unsigned char *old, unsigned char **newch,
+ size_t bytes_max, size_t *n, int zlib)
+{
+ int rc;
+ z_stream z;
+
+ if ((*newch = CAST(unsigned char *, malloc(bytes_max + 1))) == NULL)
+ return makeerror(newch, n, "No buffer, %s", strerror(errno));
+
+ z.next_in = CCAST(Bytef *, old);
+ z.avail_in = CAST(uint32_t, *n);
+ z.next_out = *newch;
+ z.avail_out = CAST(unsigned int, bytes_max);
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = Z_NULL;
+
+ /* LINTED bug in header macro */
+ rc = zlib ? inflateInit(&z) : inflateInit2(&z, -15);
+ if (rc != Z_OK)
+ goto err;
+
+ rc = inflate(&z, Z_SYNC_FLUSH);
+ if (rc != Z_OK && rc != Z_STREAM_END)
+ goto err;
+
+ *n = (size_t)z.total_out;
+ rc = inflateEnd(&z);
+ if (rc != Z_OK)
+ goto err;
+
+ /* let's keep the nul-terminate tradition */
+ (*newch)[*n] = '\0';
+
+ return OKDATA;
+err:
+ strlcpy((char *)*newch, z.msg ? z.msg : zError(rc), bytes_max);
+ *n = strlen((char *)*newch);
+ return ERRDATA;
+}
+#endif
+
+static int
+makeerror(unsigned char **buf, size_t *len, const char *fmt, ...)
+{
+ char *msg;
+ va_list ap;
+ int rv;
+
+ va_start(ap, fmt);
+ rv = vasprintf(&msg, fmt, ap);
+ va_end(ap);
+ if (rv < 0) {
+ *buf = NULL;
+ *len = 0;
+ return NODATA;
+ }
+ *buf = (unsigned char *)msg;
+ *len = strlen(msg);
+ return ERRDATA;
+}
+
+static void
+closefd(int *fd, size_t i)
+{
+ if (fd[i] == -1)
+ return;
+ (void) close(fd[i]);
+ fd[i] = -1;
+}
+
+static void
+closep(int *fd)
+{
+ size_t i;
+ for (i = 0; i < 2; i++)
+ closefd(fd, i);
+}
+
+static void
+copydesc(int i, int *fd)
+{
+ int j = fd[i == STDIN_FILENO ? 0 : 1];
+ if (j == i)
+ return;
+ if (dup2(j, i) == -1) {
+ DPRINTF("dup(%d, %d) failed (%s)\n", j, i, strerror(errno));
+ exit(1);
+ }
+ closep(fd);
+}
+
+static void
+writechild(int fdp[3][2], const void *old, size_t n)
+{
+ int status;
+
+ closefd(fdp[STDIN_FILENO], 0);
+ /*
+ * fork again, to avoid blocking because both
+ * pipes filled
+ */
+ switch (fork()) {
+ case 0: /* child */
+ closefd(fdp[STDOUT_FILENO], 0);
+ if (swrite(fdp[STDIN_FILENO][1], old, n) != (ssize_t)n) {
+ DPRINTF("Write failed (%s)\n", strerror(errno));
+ exit(1);
+ }
+ exit(0);
+ /*NOTREACHED*/
+
+ case -1:
+ DPRINTF("Fork failed (%s)\n", strerror(errno));
+ exit(1);
+ /*NOTREACHED*/
+
+ default: /* parent */
+ if (wait(&status) == -1) {
+ DPRINTF("Wait failed (%s)\n", strerror(errno));
+ exit(1);
+ }
+ DPRINTF("Grandchild wait return %#x\n", status);
+ }
+ closefd(fdp[STDIN_FILENO], 1);
+}
+
+static ssize_t
+filter_error(unsigned char *ubuf, ssize_t n)
+{
+ char *p;
+ char *buf;
+
+ ubuf[n] = '\0';
+ buf = (char *)ubuf;
+ while (isspace((unsigned char)*buf))
+ buf++;
+ DPRINTF("Filter error[[[%s]]]\n", buf);
+ if ((p = strchr((char *)buf, '\n')) != NULL)
+ *p = '\0';
+ if ((p = strchr((char *)buf, ';')) != NULL)
+ *p = '\0';
+ if ((p = strrchr((char *)buf, ':')) != NULL) {
+ ++p;
+ while (isspace((unsigned char)*p))
+ p++;
+ n = strlen(p);
+ memmove(ubuf, p, CAST(size_t, n + 1));
+ }
+ DPRINTF("Filter error after[[[%s]]]\n", (char *)ubuf);
+ if (islower(*ubuf))
+ *ubuf = toupper(*ubuf);
+ return n;
+}
+
+private const char *
+methodname(size_t method)
+{
+#ifdef BUILTIN_DECOMPRESS
+ /* FIXME: This doesn't cope with bzip2 */
+ if (method == 2 || compr[method].maglen == 0)
+ return "zlib";
+#endif
+ return compr[method].argv[0];
+}
+
+private int
+uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
+ unsigned char **newch, size_t* n)
+{
+ int fdp[3][2];
+ int status, rv;
+ size_t i;
+ ssize_t r;
+
+#ifdef BUILTIN_DECOMPRESS
+ /* FIXME: This doesn't cope with bzip2 */
+ if (method == 2)
+ return uncompressgzipped(old, newch, bytes_max, n);
+ if (compr[method].maglen == 0)
+ return uncompresszlib(old, newch, bytes_max, n, 1);
+#endif
+ (void)fflush(stdout);
+ (void)fflush(stderr);
+
+ for (i = 0; i < __arraycount(fdp); i++)
+ fdp[i][0] = fdp[i][1] = -1;
+
+ if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
+ pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
+ closep(fdp[STDIN_FILENO]);
+ closep(fdp[STDOUT_FILENO]);
+ return makeerror(newch, n, "Cannot create pipe, %s",
+ strerror(errno));
+ }
+ switch (fork()) {
+ case 0: /* child */
+ if (fd != -1) {
+ fdp[STDIN_FILENO][0] = fd;
+ (void) lseek(fd, (off_t)0, SEEK_SET);
+ }
+
+ for (i = 0; i < __arraycount(fdp); i++)
+ copydesc(CAST(int, i), fdp[i]);
+
+ (void)execvp(compr[method].argv[0],
+ (char *const *)(intptr_t)compr[method].argv);
+ dprintf(STDERR_FILENO, "exec `%s' failed, %s",
+ compr[method].argv[0], strerror(errno));
+ exit(1);
+ /*NOTREACHED*/
+ case -1:
+ return makeerror(newch, n, "Cannot fork, %s",
+ strerror(errno));
+
+ default: /* parent */
+ for (i = 1; i < __arraycount(fdp); i++)
+ closefd(fdp[i], 1);
+
+ /* Write the buffer data to the child, if we don't have fd */
+ if (fd == -1)
+ writechild(fdp, old, *n);
+
+ *newch = CAST(unsigned char *, malloc(bytes_max + 1));
+ if (*newch == NULL) {
+ rv = makeerror(newch, n, "No buffer, %s",
+ strerror(errno));
+ goto err;
+ }
+ rv = OKDATA;
+ if ((r = sread(fdp[STDOUT_FILENO][0], *newch, bytes_max, 0)) > 0)
+ break;
+ DPRINTF("Read stdout failed %d (%s)\n", fdp[STDOUT_FILENO][0],
+ r != -1 ? strerror(errno) : "no data");
+
+ rv = ERRDATA;
+ if (r == 0 &&
+ (r = sread(fdp[STDERR_FILENO][0], *newch, bytes_max, 0)) > 0)
+ {
+ r = filter_error(*newch, r);
+ break;
+ }
+ free(*newch);
+ if (r == 0)
+ rv = makeerror(newch, n, "Read failed, %s",
+ strerror(errno));
+ else
+ rv = makeerror(newch, n, "No data");
+ goto err;
+ }
+
+ *n = r;
+ /* NUL terminate, as every buffer is handled here. */
+ (*newch)[*n] = '\0';
+err:
+ closefd(fdp[STDIN_FILENO], 1);
+ closefd(fdp[STDOUT_FILENO], 0);
+ closefd(fdp[STDERR_FILENO], 0);
+ if (wait(&status) == -1) {
+ free(*newch);
+ rv = makeerror(newch, n, "Wait failed, %s", strerror(errno));
+ DPRINTF("Child wait return %#x\n", status);
+ } else if (!WIFEXITED(status)) {
+ DPRINTF("Child not exited (%#x)\n", status);
+ } else if (WEXITSTATUS(status) != 0) {
+ DPRINTF("Child exited (%#x)\n", WEXITSTATUS(status));
+ }
+
+ closefd(fdp[STDIN_FILENO], 0);
+ DPRINTF("Returning %p n=%zu rv=%d\n", *newch, *n, rv);
+
+ return rv;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/ctime_r.c b/node_modules/mmmagic/deps/libmagic/src/ctime_r.c
new file mode 100644
index 0000000..ca7ad2f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/ctime_r.c
@@ -0,0 +1,19 @@
+/* $File: ctime_r.c,v 1.1 2012/05/15 17:14:36 christos Exp $ */
+
+#include "file.h"
+#ifndef lint
+FILE_RCSID("@(#)$File: ctime_r.c,v 1.1 2012/05/15 17:14:36 christos Exp $")
+#endif /* lint */
+#include <time.h>
+#include <string.h>
+
+/* ctime_r is not thread-safe anyway */
+char *
+ctime_r(const time_t *t, char *dst)
+{
+ char *p = ctime(t);
+ if (p == NULL)
+ return NULL;
+ memcpy(dst, p, 26);
+ return dst;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/der.c b/node_modules/mmmagic/deps/libmagic/src/der.c
new file mode 100644
index 0000000..e7ca16e
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/der.c
@@ -0,0 +1,409 @@
+/*-
+ * Copyright (c) 2016 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * DER (Distinguished Encoding Rules) Parser
+ *
+ * Sources:
+ * https://en.wikipedia.org/wiki/X.690
+ * http://fm4dd.com/openssl/certexamples.htm
+ * http://blog.engelke.com/2014/10/17/parsing-ber-and-der-encoded-asn-1-objects/
+ */
+#ifndef TEST_DER
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: der.c,v 1.12 2017/02/10 18:14:01 christos Exp $")
+#endif
+#endif
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+// XXX: addition by mscdex
+#ifdef _MSC_VER
+#define __func__ __FUNCTION__
+#endif
+
+#ifndef TEST_DER
+#include "magic.h"
+#include "der.h"
+#else
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <err.h>
+#endif
+
+#define DER_BAD ((uint32_t)-1)
+
+#define DER_CLASS_UNIVERSAL 0
+#define DER_CLASS_APPLICATION 1
+#define DER_CLASS_CONTEXT 2
+#define DER_CLASS_PRIVATE 3
+#ifdef DEBUG_DER
+static const char der_class[] = "UACP";
+#endif
+
+#define DER_TYPE_PRIMITIVE 0
+#define DER_TYPE_CONSTRUCTED 1
+#ifdef DEBUG_DER
+static const char der_type[] = "PC";
+#endif
+
+#define DER_TAG_EOC 0x00
+#define DER_TAG_BOOLEAN 0x01
+#define DER_TAG_INTEGER 0x02
+#define DER_TAG_BIT STRING 0x03
+#define DER_TAG_OCTET_STRING 0x04
+#define DER_TAG_NULL 0x05
+#define DER_TAG_OBJECT_IDENTIFIER 0x06
+#define DER_TAG_OBJECT_DESCRIPTOR 0x07
+#define DER_TAG_EXTERNAL 0x08
+#define DER_TAG_REAL 0x09
+#define DER_TAG_ENUMERATED 0x0a
+#define DER_TAG_EMBEDDED_PDV 0x0b
+#define DER_TAG_UTF8_STRING 0x0c
+#define DER_TAG_RELATIVE_OID 0x0d
+#define DER_TAG_RESERVED_1 0x0e
+#define DER_TAG_RESERVED_2 0x0f
+#define DER_TAG_SEQUENCE 0x10
+#define DER_TAG_SET 0x11
+#define DER_TAG_NUMERIC_STRING 0x12
+#define DER_TAG_PRINTABLE_STRING 0x13
+#define DER_TAG_T61_STRING 0x14
+#define DER_TAG_VIDEOTEX_STRING 0x15
+#define DER_TAG_IA5_STRING 0x16
+#define DER_TAG_UTCTIME 0x17
+#define DER_TAG_GENERALIZED_TIME 0x18
+#define DER_TAG_GRAPHIC_STRING 0x19
+#define DER_TAG_VISIBLE_STRING 0x1a
+#define DER_TAG_GENERAL_STRING 0x1b
+#define DER_TAG_UNIVERSAL_STRING 0x1c
+#define DER_TAG_CHARACTER_STRING 0x1d
+#define DER_TAG_BMP_STRING 0x1e
+#define DER_TAG_LONG 0x1f
+
+static const char *der__tag[] = {
+ "eoc", "bool", "int", "bit_str", "octet_str",
+ "null", "obj_id", "obj_desc", "ext", "real",
+ "enum", "embed", "utf8_str", "oid", "res1",
+ "res2", "seq", "set", "num_str", "prt_str",
+ "t61_str", "vid_str", "ia5_str", "utc_time",
+ "gen_time", "gr_str", "vis_str", "gen_str",
+ "char_str", "bmp_str", "long"
+};
+
+#ifdef DEBUG_DER
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
+
+#ifdef TEST_DER
+static uint8_t
+getclass(uint8_t c)
+{
+ return c >> 6;
+}
+
+static uint8_t
+gettype(uint8_t c)
+{
+ return (c >> 5) & 1;
+}
+#endif
+
+static uint32_t
+gettag(const uint8_t *c, size_t *p, size_t l)
+{
+ uint32_t tag;
+
+ if (*p >= l)
+ return DER_BAD;
+
+ tag = c[(*p)++] & 0x1f;
+
+ if (tag != 0x1f)
+ return tag;
+
+ if (*p >= l)
+ return DER_BAD;
+
+ while (c[*p] >= 0x80) {
+ tag = tag * 128 + c[(*p)++] - 0x80;
+ if (*p >= l)
+ return DER_BAD;
+ }
+ return tag;
+}
+
+/*
+ * Read the length of a DER tag from the input.
+ *
+ * `c` is the input, `p` is an output parameter that specifies how much of the
+ * input we consumed, and `l` is the maximum input length.
+ *
+ * Returns the length, or DER_BAD if the end of the input is reached or the
+ * length exceeds the remaining input.
+ */
+static uint32_t
+getlength(const uint8_t *c, size_t *p, size_t l)
+{
+ uint8_t digits, i;
+ size_t len;
+ int is_onebyte_result;
+
+ if (*p >= l)
+ return DER_BAD;
+
+ /*
+ * Digits can either be 0b0 followed by the result, or 0b1
+ * followed by the number of digits of the result. In either case,
+ * we verify that we can read so many bytes from the input.
+ */
+ is_onebyte_result = (c[*p] & 0x80) == 0;
+ digits = c[(*p)++] & 0x7f;
+ if (*p + digits >= l)
+ return DER_BAD;
+
+ if (is_onebyte_result)
+ return digits;
+
+ /*
+ * Decode len. We've already verified that we're allowed to read
+ * `digits` bytes.
+ */
+ len = 0;
+ for (i = 0; i < digits; i++)
+ len = (len << 8) | c[(*p)++];
+
+ if (*p + len >= l)
+ return DER_BAD;
+ return CAST(uint32_t, len);
+}
+
+static const char *
+der_tag(char *buf, size_t len, uint32_t tag)
+{
+ if (tag < DER_TAG_LONG)
+ strlcpy(buf, der__tag[tag], len);
+ else
+ snprintf(buf, len, "%#x", tag);
+ return buf;
+}
+
+#ifndef TEST_DER
+static int
+der_data(char *buf, size_t blen, uint32_t tag, const void *q, uint32_t len)
+{
+ const uint8_t *d = CAST(const uint8_t *, q);
+ switch (tag) {
+ case DER_TAG_PRINTABLE_STRING:
+ case DER_TAG_UTF8_STRING:
+ case DER_TAG_IA5_STRING:
+ case DER_TAG_UTCTIME:
+ return snprintf(buf, blen, "%.*s", len, (const char *)q);
+ default:
+ break;
+ }
+
+ for (uint32_t i = 0; i < len; i++) {
+ uint32_t z = i << 1;
+ if (z < blen - 2)
+ snprintf(buf + z, blen - z, "%.2x", d[i]);
+ }
+ return len * 2;
+}
+
+int32_t
+der_offs(struct magic_set *ms, struct magic *m, size_t nbytes)
+{
+ const uint8_t *b = RCAST(const uint8_t *, ms->search.s);
+ size_t offs = 0, len = ms->search.s_len ? ms->search.s_len : nbytes;
+
+ if (gettag(b, &offs, len) == DER_BAD)
+ return -1;
+ DPRINTF(("%s1: %d %zu %u\n", __func__, ms->offset, offs, m->offset));
+
+ uint32_t tlen = getlength(b, &offs, len);
+ if (tlen == DER_BAD)
+ return -1;
+ DPRINTF(("%s2: %d %zu %u\n", __func__, ms->offset, offs, tlen));
+
+ offs += ms->offset + m->offset;
+ DPRINTF(("cont_level = %d\n", m->cont_level));
+#ifdef DEBUG_DER
+ for (size_t i = 0; i < m->cont_level; i++)
+ printf("cont_level[%zu] = %u\n", i, ms->c.li[i].off);
+#endif
+ if (m->cont_level != 0) {
+ if (offs + tlen > nbytes)
+ return -1;
+ ms->c.li[m->cont_level - 1].off = CAST(int, offs + tlen);
+ DPRINTF(("cont_level[%u] = %u\n", m->cont_level - 1,
+ ms->c.li[m->cont_level - 1].off));
+ }
+ return CAST(int32_t, offs);
+}
+
+int
+der_cmp(struct magic_set *ms, struct magic *m)
+{
+ const uint8_t *b = RCAST(const uint8_t *, ms->search.s);
+ const char *s = m->value.s;
+ size_t offs = 0, len = ms->search.s_len;
+ uint32_t tag, tlen;
+ char buf[128];
+
+ tag = gettag(b, &offs, len);
+ if (tag == DER_BAD)
+ return -1;
+
+ tlen = getlength(b, &offs, len);
+ if (tlen == DER_BAD)
+ return -1;
+
+ der_tag(buf, sizeof(buf), tag);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "%s: tag %p got=%s exp=%s\n", __func__, b,
+ buf, s);
+ size_t slen = strlen(buf);
+
+ if (strncmp(buf, s, slen) != 0)
+ return 0;
+
+ s += slen;
+
+again:
+ switch (*s) {
+ case '\0':
+ return 1;
+ case '=':
+ s++;
+ goto val;
+ default:
+ if (!isdigit((unsigned char)*s))
+ return 0;
+
+ slen = 0;
+ do
+ slen = slen * 10 + *s - '0';
+ while (isdigit((unsigned char)*++s));
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "%s: len %zu %u\n", __func__,
+ slen, tlen);
+ if (tlen != slen)
+ return 0;
+ goto again;
+ }
+val:
+ DPRINTF(("%s: before data %zu %u\n", __func__, offs, tlen));
+ der_data(buf, sizeof(buf), tag, b + offs, tlen);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "%s: data %s %s\n", __func__, buf, s);
+ if (strcmp(buf, s) != 0 && strcmp("x", s) != 0)
+ return 0;
+ strlcpy(ms->ms_value.s, buf, sizeof(ms->ms_value.s));
+ return 1;
+}
+#endif
+
+#ifdef TEST_DER
+static void
+printtag(uint32_t tag, const void *q, uint32_t len)
+{
+ const uint8_t *d = q;
+ switch (tag) {
+ case DER_TAG_PRINTABLE_STRING:
+ case DER_TAG_UTF8_STRING:
+ printf("%.*s\n", len, (const char *)q);
+ return;
+ default:
+ break;
+ }
+
+ for (uint32_t i = 0; i < len; i++)
+ printf("%.2x", d[i]);
+ printf("\n");
+}
+
+static void
+printdata(size_t level, const void *v, size_t x, size_t l)
+{
+ const uint8_t *p = v, *ep = p + l;
+ size_t ox;
+ char buf[128];
+
+ while (p + x < ep) {
+ const uint8_t *q;
+ uint8_t c = getclass(p[x]);
+ uint8_t t = gettype(p[x]);
+ ox = x;
+ if (x != 0)
+ printf("%.2x %.2x %.2x\n", p[x - 1], p[x], p[x + 1]);
+ uint32_t tag = gettag(p, &x, ep - p + x);
+ if (p + x >= ep)
+ break;
+ uint32_t len = getlength(p, &x, ep - p + x);
+
+ printf("%zu %zu-%zu %c,%c,%s,%u:", level, ox, x,
+ der_class[c], der_type[t],
+ der_tag(buf, sizeof(buf), tag), len);
+ q = p + x;
+ if (p + len > ep)
+ errx(EXIT_FAILURE, "corrupt der");
+ printtag(tag, q, len);
+ if (t != DER_TYPE_PRIMITIVE)
+ printdata(level + 1, p, x, len + x);
+ x += len;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fd;
+ struct stat st;
+ size_t l;
+ void *p;
+
+ if ((fd = open(argv[1], O_RDONLY)) == -1)
+ err(EXIT_FAILURE, "open `%s'", argv[1]);
+ if (fstat(fd, &st) == -1)
+ err(EXIT_FAILURE, "stat `%s'", argv[1]);
+ l = (size_t)st.st_size;
+ if ((p = mmap(NULL, l, PROT_READ, MAP_FILE, fd, 0)) == MAP_FAILED)
+ err(EXIT_FAILURE, "mmap `%s'", argv[1]);
+
+ printdata(0, p, 0, l);
+ munmap(p, l);
+ return 0;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/der.h b/node_modules/mmmagic/deps/libmagic/src/der.h
new file mode 100644
index 0000000..3333239
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/der.h
@@ -0,0 +1,28 @@
+/*-
+ * Copyright (c) 2016 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+extern int der_offs(struct magic_set *, struct magic *, size_t);
+extern int der_cmp(struct magic_set *, struct magic *);
diff --git a/node_modules/mmmagic/deps/libmagic/src/dprintf.c b/node_modules/mmmagic/deps/libmagic/src/dprintf.c
new file mode 100644
index 0000000..425bacd
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/dprintf.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: dprintf.c,v 1.1 2015/11/13 15:36:14 christos Exp $")
+#endif /* lint */
+
+#include <assert.h>
+// XXX: change by mscdex
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+
+int
+dprintf(int fd, const char *fmt, ...)
+{
+ va_list ap;
+ /* Simpler than using vasprintf() here, since we never need more */
+ char buf[1024];
+ int len;
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if ((size_t)len >= sizeof(buf))
+ return -1;
+
+ if (write(fd, buf, (size_t)len) != len)
+ return -1;
+
+ return len;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/elfclass.h b/node_modules/mmmagic/deps/libmagic/src/elfclass.h
new file mode 100644
index 0000000..5360b0b
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/elfclass.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) Christos Zoulas 2008.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+ if (nbytes <= sizeof(elfhdr))
+ return 0;
+
+ u.l = 1;
+ (void)memcpy(&elfhdr, buf, sizeof elfhdr);
+ swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
+
+ type = elf_getu16(swap, elfhdr.e_type);
+ notecount = ms->elf_notes_max;
+ switch (type) {
+#ifdef ELFCORE
+ case ET_CORE:
+ phnum = elf_getu16(swap, elfhdr.e_phnum);
+ if (phnum > ms->elf_phnum_max)
+ return toomany(ms, "program headers", phnum);
+ flags |= FLAGS_IS_CORE;
+ if (dophn_core(ms, clazz, swap, fd,
+ (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
+ (size_t)elf_getu16(swap, elfhdr.e_phentsize),
+ fsize, &flags, &notecount) == -1)
+ return -1;
+ break;
+#endif
+ case ET_EXEC:
+ case ET_DYN:
+ phnum = elf_getu16(swap, elfhdr.e_phnum);
+ if (phnum > ms->elf_phnum_max)
+ return toomany(ms, "program", phnum);
+ shnum = elf_getu16(swap, elfhdr.e_shnum);
+ if (shnum > ms->elf_shnum_max)
+ return toomany(ms, "section", shnum);
+ if (dophn_exec(ms, clazz, swap, fd,
+ (off_t)elf_getu(swap, elfhdr.e_phoff), phnum,
+ (size_t)elf_getu16(swap, elfhdr.e_phentsize),
+ fsize, shnum, &flags, &notecount) == -1)
+ return -1;
+ /*FALLTHROUGH*/
+ case ET_REL:
+ shnum = elf_getu16(swap, elfhdr.e_shnum);
+ if (shnum > ms->elf_shnum_max)
+ return toomany(ms, "section headers", shnum);
+ if (doshn(ms, clazz, swap, fd,
+ (off_t)elf_getu(swap, elfhdr.e_shoff), shnum,
+ (size_t)elf_getu16(swap, elfhdr.e_shentsize),
+ fsize, elf_getu16(swap, elfhdr.e_machine),
+ (int)elf_getu16(swap, elfhdr.e_shstrndx),
+ &flags, &notecount) == -1)
+ return -1;
+ break;
+
+ default:
+ break;
+ }
+ if (notecount == 0)
+ return toomany(ms, "notes", ms->elf_notes_max);
+ return 1;
diff --git a/node_modules/mmmagic/deps/libmagic/src/encoding.c b/node_modules/mmmagic/deps/libmagic/src/encoding.c
new file mode 100644
index 0000000..3c116cd
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/encoding.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Encoding -- determine the character encoding of a text file.
+ *
+ * Joerg Wunsch <joerg@freebsd.org> wrote the original support for 8-bit
+ * international characters.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: encoding.c,v 1.13 2015/06/04 19:16:28 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <string.h>
+#include <memory.h>
+#include <stdlib.h>
+
+
+private int looks_ascii(const unsigned char *, size_t, unichar *, size_t *);
+private int looks_utf8_with_BOM(const unsigned char *, size_t, unichar *,
+ size_t *);
+private int looks_utf7(const unsigned char *, size_t, unichar *, size_t *);
+private int looks_ucs16(const unsigned char *, size_t, unichar *, size_t *);
+private int looks_latin1(const unsigned char *, size_t, unichar *, size_t *);
+private int looks_extended(const unsigned char *, size_t, unichar *, size_t *);
+private void from_ebcdic(const unsigned char *, size_t, unsigned char *);
+
+#ifdef DEBUG_ENCODING
+#define DPRINTF(a) printf a
+#else
+#define DPRINTF(a)
+#endif
+
+/*
+ * Try to determine whether text is in some character code we can
+ * identify. Each of these tests, if it succeeds, will leave
+ * the text converted into one-unichar-per-character Unicode in
+ * ubuf, and the number of characters converted in ulen.
+ */
+protected int
+file_encoding(struct magic_set *ms, const unsigned char *buf, size_t nbytes, unichar **ubuf, size_t *ulen, const char **code, const char **code_mime, const char **type)
+{
+ size_t mlen;
+ int rv = 1, ucs_type;
+ unsigned char *nbuf = NULL;
+
+ *type = "text";
+ *ulen = 0;
+ *code = "unknown";
+ *code_mime = "binary";
+
+ mlen = (nbytes + 1) * sizeof((*ubuf)[0]);
+ if ((*ubuf = CAST(unichar *, calloc((size_t)1, mlen))) == NULL) {
+ file_oomem(ms, mlen);
+ goto done;
+ }
+ mlen = (nbytes + 1) * sizeof(nbuf[0]);
+ if ((nbuf = CAST(unsigned char *, calloc((size_t)1, mlen))) == NULL) {
+ file_oomem(ms, mlen);
+ goto done;
+ }
+
+ if (looks_ascii(buf, nbytes, *ubuf, ulen)) {
+ if (looks_utf7(buf, nbytes, *ubuf, ulen) > 0) {
+ DPRINTF(("utf-7 %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "UTF-7 Unicode";
+ *code_mime = "utf-7";
+ } else {
+ DPRINTF(("ascii %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "ASCII";
+ *code_mime = "us-ascii";
+ }
+ } else if (looks_utf8_with_BOM(buf, nbytes, *ubuf, ulen) > 0) {
+ DPRINTF(("utf8/bom %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "UTF-8 Unicode (with BOM)";
+ *code_mime = "utf-8";
+ } else if (file_looks_utf8(buf, nbytes, *ubuf, ulen) > 1) {
+ DPRINTF(("utf8 %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "UTF-8 Unicode";
+ *code_mime = "utf-8";
+ } else if ((ucs_type = looks_ucs16(buf, nbytes, *ubuf, ulen)) != 0) {
+ if (ucs_type == 1) {
+ *code = "Little-endian UTF-16 Unicode";
+ *code_mime = "utf-16le";
+ } else {
+ *code = "Big-endian UTF-16 Unicode";
+ *code_mime = "utf-16be";
+ }
+ DPRINTF(("ucs16 %" SIZE_T_FORMAT "u\n", *ulen));
+ } else if (looks_latin1(buf, nbytes, *ubuf, ulen)) {
+ DPRINTF(("latin1 %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "ISO-8859";
+ *code_mime = "iso-8859-1";
+ } else if (looks_extended(buf, nbytes, *ubuf, ulen)) {
+ DPRINTF(("extended %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "Non-ISO extended-ASCII";
+ *code_mime = "unknown-8bit";
+ } else {
+ from_ebcdic(buf, nbytes, nbuf);
+
+ if (looks_ascii(nbuf, nbytes, *ubuf, ulen)) {
+ DPRINTF(("ebcdic %" SIZE_T_FORMAT "u\n", *ulen));
+ *code = "EBCDIC";
+ *code_mime = "ebcdic";
+ } else if (looks_latin1(nbuf, nbytes, *ubuf, ulen)) {
+ DPRINTF(("ebcdic/international %" SIZE_T_FORMAT "u\n",
+ *ulen));
+ *code = "International EBCDIC";
+ *code_mime = "ebcdic";
+ } else { /* Doesn't look like text at all */
+ DPRINTF(("binary\n"));
+ rv = 0;
+ *type = "binary";
+ }
+ }
+
+ done:
+ free(nbuf);
+
+ return rv;
+}
+
+/*
+ * This table reflects a particular philosophy about what constitutes
+ * "text," and there is room for disagreement about it.
+ *
+ * Version 3.31 of the file command considered a file to be ASCII if
+ * each of its characters was approved by either the isascii() or
+ * isalpha() function. On most systems, this would mean that any
+ * file consisting only of characters in the range 0x00 ... 0x7F
+ * would be called ASCII text, but many systems might reasonably
+ * consider some characters outside this range to be alphabetic,
+ * so the file command would call such characters ASCII. It might
+ * have been more accurate to call this "considered textual on the
+ * local system" than "ASCII."
+ *
+ * It considered a file to be "International language text" if each
+ * of its characters was either an ASCII printing character (according
+ * to the real ASCII standard, not the above test), a character in
+ * the range 0x80 ... 0xFF, or one of the following control characters:
+ * backspace, tab, line feed, vertical tab, form feed, carriage return,
+ * escape. No attempt was made to determine the language in which files
+ * of this type were written.
+ *
+ *
+ * The table below considers a file to be ASCII if all of its characters
+ * are either ASCII printing characters (again, according to the X3.4
+ * standard, not isascii()) or any of the following controls: bell,
+ * backspace, tab, line feed, form feed, carriage return, esc, nextline.
+ *
+ * I include bell because some programs (particularly shell scripts)
+ * use it literally, even though it is rare in normal text. I exclude
+ * vertical tab because it never seems to be used in real text. I also
+ * include, with hesitation, the X3.64/ECMA-43 control nextline (0x85),
+ * because that's what the dd EBCDIC->ASCII table maps the EBCDIC newline
+ * character to. It might be more appropriate to include it in the 8859
+ * set instead of the ASCII set, but it's got to be included in *something*
+ * we recognize or EBCDIC files aren't going to be considered textual.
+ * Some old Unix source files use SO/SI (^N/^O) to shift between Greek
+ * and Latin characters, so these should possibly be allowed. But they
+ * make a real mess on VT100-style displays if they're not paired properly,
+ * so we are probably better off not calling them text.
+ *
+ * A file is considered to be ISO-8859 text if its characters are all
+ * either ASCII, according to the above definition, or printing characters
+ * from the ISO-8859 8-bit extension, characters 0xA0 ... 0xFF.
+ *
+ * Finally, a file is considered to be international text from some other
+ * character code if its characters are all either ISO-8859 (according to
+ * the above definition) or characters in the range 0x80 ... 0x9F, which
+ * ISO-8859 considers to be control characters but the IBM PC and Macintosh
+ * consider to be printing characters.
+ */
+
+#define F 0 /* character never appears in text */
+#define T 1 /* character appears in plain ASCII text */
+#define I 2 /* character appears in ISO-8859 text */
+#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+private char text_chars[256] = {
+ /* BEL BS HT LF VT FF CR */
+ F, F, F, F, F, F, F, T, T, T, T, T, T, T, F, F, /* 0x0X */
+ /* ESC */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ /* NEL */
+ X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
+};
+
+private int
+looks_ascii(const unsigned char *buf, size_t nbytes, unichar *ubuf,
+ size_t *ulen)
+{
+ size_t i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nbytes; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+
+private int
+looks_latin1(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen)
+{
+ size_t i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nbytes; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T && t != I)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+
+private int
+looks_extended(const unsigned char *buf, size_t nbytes, unichar *ubuf,
+ size_t *ulen)
+{
+ size_t i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nbytes; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T && t != I && t != X)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+
+/*
+ * Decide whether some text looks like UTF-8. Returns:
+ *
+ * -1: invalid UTF-8
+ * 0: uses odd control characters, so doesn't look like text
+ * 1: 7-bit text
+ * 2: definitely UTF-8 text (valid high-bit set bytes)
+ *
+ * If ubuf is non-NULL on entry, text is decoded into ubuf, *ulen;
+ * ubuf must be big enough!
+ */
+protected int
+file_looks_utf8(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen)
+{
+ size_t i;
+ int n;
+ unichar c;
+ int gotone = 0, ctrl = 0;
+
+ if (ubuf)
+ *ulen = 0;
+
+ for (i = 0; i < nbytes; i++) {
+ if ((buf[i] & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
+ /*
+ * Even if the whole file is valid UTF-8 sequences,
+ * still reject it if it uses weird control characters.
+ */
+
+ if (text_chars[buf[i]] != T)
+ ctrl = 1;
+
+ if (ubuf)
+ ubuf[(*ulen)++] = buf[i];
+ } else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+ return -1;
+ } else { /* 11xxxxxx begins UTF-8 */
+ int following;
+
+ if ((buf[i] & 0x20) == 0) { /* 110xxxxx */
+ c = buf[i] & 0x1f;
+ following = 1;
+ } else if ((buf[i] & 0x10) == 0) { /* 1110xxxx */
+ c = buf[i] & 0x0f;
+ following = 2;
+ } else if ((buf[i] & 0x08) == 0) { /* 11110xxx */
+ c = buf[i] & 0x07;
+ following = 3;
+ } else if ((buf[i] & 0x04) == 0) { /* 111110xx */
+ c = buf[i] & 0x03;
+ following = 4;
+ } else if ((buf[i] & 0x02) == 0) { /* 1111110x */
+ c = buf[i] & 0x01;
+ following = 5;
+ } else
+ return -1;
+
+ for (n = 0; n < following; n++) {
+ i++;
+ if (i >= nbytes)
+ goto done;
+
+ if ((buf[i] & 0x80) == 0 || (buf[i] & 0x40))
+ return -1;
+
+ c = (c << 6) + (buf[i] & 0x3f);
+ }
+
+ if (ubuf)
+ ubuf[(*ulen)++] = c;
+ gotone = 1;
+ }
+ }
+done:
+ return ctrl ? 0 : (gotone ? 2 : 1);
+}
+
+/*
+ * Decide whether some text looks like UTF-8 with BOM. If there is no
+ * BOM, return -1; otherwise return the result of looks_utf8 on the
+ * rest of the text.
+ */
+private int
+looks_utf8_with_BOM(const unsigned char *buf, size_t nbytes, unichar *ubuf,
+ size_t *ulen)
+{
+ if (nbytes > 3 && buf[0] == 0xef && buf[1] == 0xbb && buf[2] == 0xbf)
+ return file_looks_utf8(buf + 3, nbytes - 3, ubuf, ulen);
+ else
+ return -1;
+}
+
+private int
+looks_utf7(const unsigned char *buf, size_t nbytes, unichar *ubuf, size_t *ulen)
+{
+ if (nbytes > 4 && buf[0] == '+' && buf[1] == '/' && buf[2] == 'v')
+ switch (buf[3]) {
+ case '8':
+ case '9':
+ case '+':
+ case '/':
+ if (ubuf)
+ *ulen = 0;
+ return 1;
+ default:
+ return -1;
+ }
+ else
+ return -1;
+}
+
+private int
+looks_ucs16(const unsigned char *buf, size_t nbytes, unichar *ubuf,
+ size_t *ulen)
+{
+ int bigend;
+ size_t i;
+
+ if (nbytes < 2)
+ return 0;
+
+ if (buf[0] == 0xff && buf[1] == 0xfe)
+ bigend = 0;
+ else if (buf[0] == 0xfe && buf[1] == 0xff)
+ bigend = 1;
+ else
+ return 0;
+
+ *ulen = 0;
+
+ for (i = 2; i + 1 < nbytes; i += 2) {
+ /* XXX fix to properly handle chars > 65536 */
+
+ if (bigend)
+ ubuf[(*ulen)++] = buf[i + 1] + 256 * buf[i];
+ else
+ ubuf[(*ulen)++] = buf[i] + 256 * buf[i + 1];
+
+ if (ubuf[*ulen - 1] == 0xfffe)
+ return 0;
+ if (ubuf[*ulen - 1] < 128 &&
+ text_chars[(size_t)ubuf[*ulen - 1]] != T)
+ return 0;
+ }
+
+ return 1 + bigend;
+}
+
+#undef F
+#undef T
+#undef I
+#undef X
+
+/*
+ * This table maps each EBCDIC character to an (8-bit extended) ASCII
+ * character, as specified in the rationale for the dd(1) command in
+ * draft 11.2 (September, 1991) of the POSIX P1003.2 standard.
+ *
+ * Unfortunately it does not seem to correspond exactly to any of the
+ * five variants of EBCDIC documented in IBM's _Enterprise Systems
+ * Architecture/390: Principles of Operation_, SA22-7201-06, Seventh
+ * Edition, July, 1999, pp. I-1 - I-4.
+ *
+ * Fortunately, though, all versions of EBCDIC, including this one, agree
+ * on most of the printing characters that also appear in (7-bit) ASCII.
+ * Of these, only '|', '!', '~', '^', '[', and ']' are in question at all.
+ *
+ * Fortunately too, there is general agreement that codes 0x00 through
+ * 0x3F represent control characters, 0x41 a nonbreaking space, and the
+ * remainder printing characters.
+ *
+ * This is sufficient to allow us to identify EBCDIC text and to distinguish
+ * between old-style and internationalized examples of text.
+ */
+
+private unsigned char ebcdic_to_ascii[] = {
+ 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
+128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
+144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
+' ', 160, 161, 162, 163, 164, 165, 166, 167, 168, 213, '.', '<', '(', '+', '|',
+'&', 169, 170, 171, 172, 173, 174, 175, 176, 177, '!', '$', '*', ')', ';', '~',
+'-', '/', 178, 179, 180, 181, 182, 183, 184, 185, 203, ',', '%', '_', '>', '?',
+186, 187, 188, 189, 190, 191, 192, 193, 194, '`', ':', '#', '@', '\'','=', '"',
+195, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 196, 197, 198, 199, 200, 201,
+202, 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', '^', 204, 205, 206, 207, 208,
+209, 229, 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 210, 211, 212, '[', 214, 215,
+216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, ']', 230, 231,
+'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 232, 233, 234, 235, 236, 237,
+'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 238, 239, 240, 241, 242, 243,
+'\\',159, 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 244, 245, 246, 247, 248, 249,
+'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 250, 251, 252, 253, 254, 255
+};
+
+#ifdef notdef
+/*
+ * The following EBCDIC-to-ASCII table may relate more closely to reality,
+ * or at least to modern reality. It comes from
+ *
+ * http://ftp.s390.ibm.com/products/oe/bpxqp9.html
+ *
+ * and maps the characters of EBCDIC code page 1047 (the code used for
+ * Unix-derived software on IBM's 390 systems) to the corresponding
+ * characters from ISO 8859-1.
+ *
+ * If this table is used instead of the above one, some of the special
+ * cases for the NEL character can be taken out of the code.
+ */
+
+private unsigned char ebcdic_1047_to_8859[] = {
+0x00,0x01,0x02,0x03,0x9C,0x09,0x86,0x7F,0x97,0x8D,0x8E,0x0B,0x0C,0x0D,0x0E,0x0F,
+0x10,0x11,0x12,0x13,0x9D,0x0A,0x08,0x87,0x18,0x19,0x92,0x8F,0x1C,0x1D,0x1E,0x1F,
+0x80,0x81,0x82,0x83,0x84,0x85,0x17,0x1B,0x88,0x89,0x8A,0x8B,0x8C,0x05,0x06,0x07,
+0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9A,0x9B,0x14,0x15,0x9E,0x1A,
+0x20,0xA0,0xE2,0xE4,0xE0,0xE1,0xE3,0xE5,0xE7,0xF1,0xA2,0x2E,0x3C,0x28,0x2B,0x7C,
+0x26,0xE9,0xEA,0xEB,0xE8,0xED,0xEE,0xEF,0xEC,0xDF,0x21,0x24,0x2A,0x29,0x3B,0x5E,
+0x2D,0x2F,0xC2,0xC4,0xC0,0xC1,0xC3,0xC5,0xC7,0xD1,0xA6,0x2C,0x25,0x5F,0x3E,0x3F,
+0xF8,0xC9,0xCA,0xCB,0xC8,0xCD,0xCE,0xCF,0xCC,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22,
+0xD8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xAB,0xBB,0xF0,0xFD,0xFE,0xB1,
+0xB0,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xAA,0xBA,0xE6,0xB8,0xC6,0xA4,
+0xB5,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xA1,0xBF,0xD0,0x5B,0xDE,0xAE,
+0xAC,0xA3,0xA5,0xB7,0xA9,0xA7,0xB6,0xBC,0xBD,0xBE,0xDD,0xA8,0xAF,0x5D,0xB4,0xD7,
+0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xAD,0xF4,0xF6,0xF2,0xF3,0xF5,
+0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xB9,0xFB,0xFC,0xF9,0xFA,0xFF,
+0x5C,0xF7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB2,0xD4,0xD6,0xD2,0xD3,0xD5,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xB3,0xDB,0xDC,0xD9,0xDA,0x9F
+};
+#endif
+
+/*
+ * Copy buf[0 ... nbytes-1] into out[], translating EBCDIC to ASCII.
+ */
+private void
+from_ebcdic(const unsigned char *buf, size_t nbytes, unsigned char *out)
+{
+ size_t i;
+
+ for (i = 0; i < nbytes; i++) {
+ out[i] = ebcdic_to_ascii[buf[i]];
+ }
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/file.c b/node_modules/mmmagic/deps/libmagic/src/file.c
new file mode 100644
index 0000000..861a824
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/file.c
@@ -0,0 +1,640 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * file - find type of a file or files - main program.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: file.c,v 1.172 2016/10/24 15:21:07 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+
+#include <stdlib.h>
+// XXX: change by mscdex
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#ifdef RESTORE_TIME
+# if (__COHERENT__ >= 0x420)
+# include <sys/utime.h>
+# else
+# ifdef USE_UTIMES
+# include <sys/time.h>
+# else
+# include <utime.h>
+# endif
+# endif
+#endif
+// XXX: change by mscdex
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for read() */
+#endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+#if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION)
+#include <getopt.h>
+#ifndef HAVE_GETOPT_LONG
+int getopt_long(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
+#endif
+#else
+#include "mygetopt.h"
+#endif
+
+#ifdef S_IFLNK
+#define FILE_FLAGS "-bcEhikLlNnprsvzZ0"
+#else
+#define FILE_FLAGS "-bcEiklNnprsvzZ0"
+#endif
+
+# define USAGE \
+ "Usage: %s [" FILE_FLAGS \
+ "] [--apple] [--extension] [--mime-encoding] [--mime-type]\n" \
+ " [-e testname] [-F separator] [-f namefile] [-m magicfiles] " \
+ "file ...\n" \
+ " %s -C [-m magicfiles]\n" \
+ " %s [--help]\n"
+
+private int /* Global command-line options */
+ bflag = 0, /* brief output format */
+ nopad = 0, /* Don't pad output */
+ nobuffer = 0, /* Do not buffer stdout */
+ nulsep = 0; /* Append '\0' to the separator */
+
+private const char *separator = ":"; /* Default field separator */
+private const struct option long_options[] = {
+#define OPT_HELP 1
+#define OPT_APPLE 2
+#define OPT_EXTENSIONS 3
+#define OPT_MIME_TYPE 4
+#define OPT_MIME_ENCODING 5
+#define OPT(shortname, longname, opt, def, doc) \
+ {longname, opt, NULL, shortname},
+#define OPT_LONGONLY(longname, opt, def, doc, id) \
+ {longname, opt, NULL, id},
+#include "file_opts.h"
+#undef OPT
+#undef OPT_LONGONLY
+ {0, 0, NULL, 0}
+};
+#define OPTSTRING "bcCde:Ef:F:hiklLm:nNpP:rsvzZ0"
+
+private const struct {
+ const char *name;
+ int value;
+} nv[] = {
+ { "apptype", MAGIC_NO_CHECK_APPTYPE },
+ { "ascii", MAGIC_NO_CHECK_ASCII },
+ { "cdf", MAGIC_NO_CHECK_CDF },
+ { "compress", MAGIC_NO_CHECK_COMPRESS },
+ { "elf", MAGIC_NO_CHECK_ELF },
+ { "encoding", MAGIC_NO_CHECK_ENCODING },
+ { "soft", MAGIC_NO_CHECK_SOFT },
+ { "tar", MAGIC_NO_CHECK_TAR },
+ { "text", MAGIC_NO_CHECK_TEXT }, /* synonym for ascii */
+ { "tokens", MAGIC_NO_CHECK_TOKENS }, /* OBSOLETE: ignored for backwards compatibility */
+};
+
+private struct {
+ const char *name;
+ int tag;
+ size_t value;
+} pm[] = {
+ { "indir", MAGIC_PARAM_INDIR_MAX, 0 },
+ { "name", MAGIC_PARAM_NAME_MAX, 0 },
+ { "elf_phnum", MAGIC_PARAM_ELF_PHNUM_MAX, 0 },
+ { "elf_shnum", MAGIC_PARAM_ELF_SHNUM_MAX, 0 },
+ { "elf_notes", MAGIC_PARAM_ELF_NOTES_MAX, 0 },
+ { "regex", MAGIC_PARAM_REGEX_MAX, 0 },
+ { "bytes", MAGIC_PARAM_BYTES_MAX, 0 },
+};
+
+private char *progname; /* used throughout */
+private int posixly;
+
+#ifdef __dead
+__dead
+#endif
+private void usage(void);
+private void docprint(const char *, int);
+#ifdef __dead
+__dead
+#endif
+private void help(void);
+
+private int unwrap(struct magic_set *, const char *);
+private int process(struct magic_set *ms, const char *, int);
+private struct magic_set *load(const char *, int);
+private void setparam(const char *);
+private void applyparam(magic_t);
+
+
+/*
+ * main - parse arguments and handle options
+ */
+int
+main(int argc, char *argv[])
+{
+ int c;
+ size_t i;
+ int action = 0, didsomefiles = 0, errflg = 0;
+ int flags = 0, e = 0;
+ struct magic_set *magic = NULL;
+ int longindex;
+ const char *magicfile = NULL; /* where the magic is */
+
+ /* makes islower etc work for other langs */
+#ifdef HAVE_SETLOCALE
+ (void)setlocale(LC_CTYPE, "");
+#endif
+
+#ifdef __EMX__
+ /* sh-like wildcard expansion! Shouldn't hurt at least ... */
+ _wildcard(&argc, &argv);
+#endif
+
+ if ((progname = strrchr(argv[0], '/')) != NULL)
+ progname++;
+ else
+ progname = argv[0];
+
+#ifdef S_IFLNK
+ posixly = getenv("POSIXLY_CORRECT") != NULL;
+ flags |= posixly ? MAGIC_SYMLINK : 0;
+#endif
+ while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
+ &longindex)) != -1)
+ switch (c) {
+ case OPT_HELP:
+ help();
+ break;
+ case OPT_APPLE:
+ flags |= MAGIC_APPLE;
+ break;
+ case OPT_EXTENSIONS:
+ flags |= MAGIC_EXTENSION;
+ break;
+ case OPT_MIME_TYPE:
+ flags |= MAGIC_MIME_TYPE;
+ break;
+ case OPT_MIME_ENCODING:
+ flags |= MAGIC_MIME_ENCODING;
+ break;
+ case '0':
+ nulsep++;
+ break;
+ case 'b':
+ bflag++;
+ break;
+ case 'c':
+ action = FILE_CHECK;
+ break;
+ case 'C':
+ action = FILE_COMPILE;
+ break;
+ case 'd':
+ flags |= MAGIC_DEBUG|MAGIC_CHECK;
+ break;
+ case 'E':
+ flags |= MAGIC_ERROR;
+ break;
+ case 'e':
+ for (i = 0; i < sizeof(nv) / sizeof(nv[0]); i++)
+ if (strcmp(nv[i].name, optarg) == 0)
+ break;
+
+ if (i == sizeof(nv) / sizeof(nv[0]))
+ errflg++;
+ else
+ flags |= nv[i].value;
+ break;
+
+ case 'f':
+ if(action)
+ usage();
+ if (magic == NULL)
+ if ((magic = load(magicfile, flags)) == NULL)
+ return 1;
+ applyparam(magic);
+ e |= unwrap(magic, optarg);
+ ++didsomefiles;
+ break;
+ case 'F':
+ separator = optarg;
+ break;
+ case 'i':
+ flags |= MAGIC_MIME;
+ break;
+ case 'k':
+ flags |= MAGIC_CONTINUE;
+ break;
+ case 'l':
+ action = FILE_LIST;
+ break;
+ case 'm':
+ magicfile = optarg;
+ break;
+ case 'n':
+ ++nobuffer;
+ break;
+ case 'N':
+ ++nopad;
+ break;
+#if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
+ case 'p':
+ flags |= MAGIC_PRESERVE_ATIME;
+ break;
+#endif
+ case 'P':
+ setparam(optarg);
+ break;
+ case 'r':
+ flags |= MAGIC_RAW;
+ break;
+ case 's':
+ flags |= MAGIC_DEVICES;
+ break;
+ case 'v':
+ if (magicfile == NULL)
+ magicfile = magic_getpath(magicfile, action);
+ (void)fprintf(stdout, "%s-%s\n", progname, VERSION);
+ (void)fprintf(stdout, "magic file from %s\n",
+ magicfile);
+ return 0;
+ case 'z':
+ flags |= MAGIC_COMPRESS;
+ break;
+
+ case 'Z':
+ flags |= MAGIC_COMPRESS|MAGIC_COMPRESS_TRANSP;
+ break;
+#ifdef S_IFLNK
+ case 'L':
+ flags |= MAGIC_SYMLINK;
+ break;
+ case 'h':
+ flags &= ~MAGIC_SYMLINK;
+ break;
+#endif
+ case '?':
+ default:
+ errflg++;
+ break;
+ }
+
+ if (errflg) {
+ usage();
+ }
+ if (e)
+ return e;
+
+ if (MAGIC_VERSION != magic_version())
+ (void)fprintf(stderr, "%s: compiled magic version [%d] "
+ "does not match with shared library magic version [%d]\n",
+ progname, MAGIC_VERSION, magic_version());
+
+ switch(action) {
+ case FILE_CHECK:
+ case FILE_COMPILE:
+ case FILE_LIST:
+ /*
+ * Don't try to check/compile ~/.magic unless we explicitly
+ * ask for it.
+ */
+ magic = magic_open(flags|MAGIC_CHECK);
+ if (magic == NULL) {
+ (void)fprintf(stderr, "%s: %s\n", progname,
+ strerror(errno));
+ return 1;
+ }
+
+
+ switch(action) {
+ case FILE_CHECK:
+ c = magic_check(magic, magicfile);
+ break;
+ case FILE_COMPILE:
+ c = magic_compile(magic, magicfile);
+ break;
+ case FILE_LIST:
+ c = magic_list(magic, magicfile);
+ break;
+ default:
+ abort();
+ }
+ if (c == -1) {
+ (void)fprintf(stderr, "%s: %s\n", progname,
+ magic_error(magic));
+ e = 1;
+ goto out;
+ }
+ goto out;
+ default:
+ if (magic == NULL)
+ if ((magic = load(magicfile, flags)) == NULL)
+ return 1;
+ applyparam(magic);
+ }
+
+ if (optind == argc) {
+ if (!didsomefiles)
+ usage();
+ }
+ else {
+ size_t j, wid, nw;
+ for (wid = 0, j = (size_t)optind; j < (size_t)argc; j++) {
+ nw = file_mbswidth(argv[j]);
+ if (nw > wid)
+ wid = nw;
+ }
+ /*
+ * If bflag is only set twice, set it depending on
+ * number of files [this is undocumented, and subject to change]
+ */
+ if (bflag == 2) {
+ bflag = optind >= argc - 1;
+ }
+ for (; optind < argc; optind++)
+ e |= process(magic, argv[optind], wid);
+ }
+
+out:
+ if (magic)
+ magic_close(magic);
+ return e;
+}
+
+private void
+applyparam(magic_t magic)
+{
+ size_t i;
+
+ for (i = 0; i < __arraycount(pm); i++) {
+ if (pm[i].value == 0)
+ continue;
+ if (magic_setparam(magic, pm[i].tag, &pm[i].value) == -1) {
+ (void)fprintf(stderr, "%s: Can't set %s %s\n", progname,
+ pm[i].name, strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+private void
+setparam(const char *p)
+{
+ size_t i;
+ char *s;
+
+ if ((s = strchr(p, '=')) == NULL)
+ goto badparm;
+
+ for (i = 0; i < __arraycount(pm); i++) {
+ if (strncmp(p, pm[i].name, s - p) != 0)
+ continue;
+ pm[i].value = atoi(s + 1);
+ return;
+ }
+badparm:
+ (void)fprintf(stderr, "%s: Unknown param %s\n", progname, p);
+ exit(1);
+}
+
+private struct magic_set *
+/*ARGSUSED*/
+load(const char *magicfile, int flags)
+{
+ struct magic_set *magic = magic_open(flags);
+ const char *e;
+
+ if (magic == NULL) {
+ (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+ return NULL;
+ }
+ if (magic_load(magic, magicfile) == -1) {
+ (void)fprintf(stderr, "%s: %s\n",
+ progname, magic_error(magic));
+ magic_close(magic);
+ return NULL;
+ }
+ if ((e = magic_error(magic)) != NULL)
+ (void)fprintf(stderr, "%s: Warning: %s\n", progname, e);
+ return magic;
+}
+
+/*
+ * unwrap -- read a file of filenames, do each one.
+ */
+private int
+unwrap(struct magic_set *ms, const char *fn)
+{
+ FILE *f;
+ ssize_t len;
+ char *line = NULL;
+ size_t llen = 0;
+ int wid = 0, cwid;
+ int e = 0;
+
+ if (strcmp("-", fn) == 0) {
+ f = stdin;
+ wid = 1;
+ } else {
+ if ((f = fopen(fn, "r")) == NULL) {
+ (void)fprintf(stderr, "%s: Cannot open `%s' (%s).\n",
+ progname, fn, strerror(errno));
+ return 1;
+ }
+
+ while ((len = getline(&line, &llen, f)) > 0) {
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ cwid = file_mbswidth(line);
+ if (cwid > wid)
+ wid = cwid;
+ }
+
+ rewind(f);
+ }
+
+ while ((len = getline(&line, &llen, f)) > 0) {
+ if (line[len - 1] == '\n')
+ line[len - 1] = '\0';
+ e |= process(ms, line, wid);
+ if(nobuffer)
+ (void)fflush(stdout);
+ }
+
+ free(line);
+ (void)fclose(f);
+ return e;
+}
+
+/*
+ * Called for each input file on the command line (or in a list of files)
+ */
+private int
+process(struct magic_set *ms, const char *inname, int wid)
+{
+ const char *type, c = nulsep > 1 ? '\0' : '\n';
+ int std_in = strcmp(inname, "-") == 0;
+
+ if (wid > 0 && !bflag) {
+ (void)printf("%s", std_in ? "/dev/stdin" : inname);
+ if (nulsep)
+ (void)putc('\0', stdout);
+ if (nulsep < 2) {
+ (void)printf("%s", separator);
+ (void)printf("%*s ",
+ (int) (nopad ? 0 : (wid - file_mbswidth(inname))),
+ "");
+ }
+ }
+
+ type = magic_file(ms, std_in ? NULL : inname);
+
+ if (type == NULL) {
+ (void)printf("ERROR: %s%c", magic_error(ms), c);
+ return 1;
+ } else {
+ (void)printf("%s%c", type, c);
+ return 0;
+ }
+}
+
+protected size_t
+file_mbswidth(const char *s)
+{
+#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
+ size_t bytesconsumed, old_n, n, width = 0;
+ mbstate_t state;
+ wchar_t nextchar;
+ (void)memset(&state, 0, sizeof(mbstate_t));
+ old_n = n = strlen(s);
+
+ while (n > 0) {
+ bytesconsumed = mbrtowc(&nextchar, s, n, &state);
+ if (bytesconsumed == (size_t)(-1) ||
+ bytesconsumed == (size_t)(-2)) {
+ /* Something went wrong, return something reasonable */
+ return old_n;
+ }
+ if (s[0] == '\n') {
+ /*
+ * do what strlen() would do, so that caller
+ * is always right
+ */
+ width++;
+ } else {
+ int w = wcwidth(nextchar);
+ if (w > 0)
+ width += w;
+ }
+
+ s += bytesconsumed, n -= bytesconsumed;
+ }
+ return width;
+#else
+ return strlen(s);
+#endif
+}
+
+private void
+usage(void)
+{
+ (void)fprintf(stderr, USAGE, progname, progname, progname);
+ exit(1);
+}
+
+private void
+defprint(int def)
+{
+ if (!def)
+ return;
+ if (((def & 1) && posixly) || ((def & 2) && !posixly))
+ fprintf(stdout, " (default)");
+ fputc('\n', stdout);
+}
+
+private void
+docprint(const char *opts, int def)
+{
+ size_t i;
+ int comma;
+ char *sp, *p;
+
+ p = strstr(opts, "%o");
+ if (p == NULL) {
+ fprintf(stdout, "%s", opts);
+ defprint(def);
+ return;
+ }
+
+ for (sp = p - 1; sp > opts && *sp == ' '; sp--)
+ continue;
+
+ fprintf(stdout, "%.*s", (int)(p - opts), opts);
+
+ comma = 0;
+ for (i = 0; i < __arraycount(nv); i++) {
+ fprintf(stdout, "%s%s", comma++ ? ", " : "", nv[i].name);
+ if (i && i % 5 == 0) {
+ fprintf(stdout, ",\n%*s", (int)(p - sp - 1), "");
+ comma = 0;
+ }
+ }
+
+ fprintf(stdout, "%s", opts + (p - opts) + 2);
+}
+
+private void
+help(void)
+{
+ (void)fputs(
+"Usage: file [OPTION...] [FILE...]\n"
+"Determine type of FILEs.\n"
+"\n", stdout);
+#define OPT(shortname, longname, opt, def, doc) \
+ fprintf(stdout, " -%c, --" longname, shortname), \
+ docprint(doc, def);
+#define OPT_LONGONLY(longname, opt, def, doc, id) \
+ fprintf(stdout, " --" longname), \
+ docprint(doc, def);
+#include "file_opts.h"
+#undef OPT
+#undef OPT_LONGONLY
+ fprintf(stdout, "\nReport bugs to http://bugs.gw.com/\n");
+ exit(0);
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/file.h b/node_modules/mmmagic/deps/libmagic/src/file.h
new file mode 100644
index 0000000..9930710
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/file.h
@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * file.h - definitions for file(1) program
+ * @(#)$File: file.h,v 1.183 2017/08/28 13:39:18 christos Exp $
+ */
+
+#ifndef __file_h__
+#define __file_h__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef HAVE_STDINT_H
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+
+// XXX: change by mscdex
+#ifdef _MSC_VER
+typedef unsigned int mode_t;
+# ifdef _WIN64
+ typedef __int64 ssize_t;
+ typedef unsigned __int64 size_t;
+# else
+ typedef _W64 int ssize_t;
+ typedef _W64 unsigned int size_t;
+# endif
+# include <io.h>
+# define access _access
+# define lseek _lseek
+# define read _read
+# define X_OK 1 /* MS access() doesn't check for execute permission. */
+# define W_OK 2 /* Check for write permission */
+# define R_OK 4 /* Check for read permission */
+# include <sys/utime.h>
+# include <dirent.h>
+# undef S_IFLNK
+# undef S_IFSOCK
+# ifndef S_IFFIFO
+# ifdef _S_IFIFO
+# define S_IFFIFO _S_IFIFO
+# else
+# define S_IFFIFO 0
+# endif
+# endif
+# define strtoull _strtoui64
+# define STDIN_FILENO 0
+#else
+# include <unistd.h>
+#endif
+
+#ifdef WIN32
+ #ifdef _WIN64
+ #define SIZE_T_FORMAT "I64"
+ #else
+ #define SIZE_T_FORMAT ""
+ #endif
+ #define INT64_T_FORMAT "I64"
+ #define INTMAX_T_FORMAT "I64"
+#else
+ #define SIZE_T_FORMAT "z"
+ #define INT64_T_FORMAT "ll"
+ #define INTMAX_T_FORMAT "j"
+#endif
+#include <stdint.h>
+#endif
+
+#include <stdio.h> /* Include that here, to make sure __P gets defined */
+#include <errno.h>
+#include <fcntl.h> /* For open and flags */
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#include <regex.h>
+#include <time.h>
+#include <sys/types.h>
+// XXX: change by mscdex
+#ifndef _MSC_VER
+#include <sys/param.h>
+#endif
+/* Do this here and now, because struct stat gets re-defined on solaris */
+#include <sys/stat.h>
+#include <stdarg.h>
+
+#define ENABLE_CONDITIONALS
+
+#ifndef MAGIC
+#define MAGIC "/etc/magic"
+#endif
+
+#if defined(__EMX__) || defined (WIN32)
+#define PATHSEP ';'
+#else
+#define PATHSEP ':'
+#endif
+
+#define private static
+
+#if HAVE_VISIBILITY && !defined(WIN32)
+#define public __attribute__ ((__visibility__("default")))
+#ifndef protected
+#define protected __attribute__ ((__visibility__("hidden")))
+#endif
+#else
+#define public
+#ifndef protected
+#define protected
+#endif
+#endif
+
+#ifndef __arraycount
+#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#ifndef __GNUC_PREREQ__
+#ifdef __GNUC__
+#define __GNUC_PREREQ__(x, y) \
+ ((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
+ (__GNUC__ > (x)))
+#else
+#define __GNUC_PREREQ__(x, y) 0
+#endif
+#endif
+
+#ifndef __GNUC__
+#ifndef __attribute__
+#define __attribute__(a)
+#endif
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef FILE_BYTES_MAX
+# define FILE_BYTES_MAX (1024 * 1024) /* how much of the file to look at */
+#endif
+#define MAXMAGIS 8192 /* max entries in any one magic file
+ or directory */
+#define MAXDESC 64 /* max len of text description/MIME type */
+#define MAXMIME 80 /* max len of text MIME type */
+#define MAXstring 96 /* max len of "string" types */
+
+#define MAGICNO 0xF11E041C
+#define VERSIONNO 14
+#define FILE_MAGICSIZE 344
+
+#define FILE_LOAD 0
+#define FILE_CHECK 1
+#define FILE_COMPILE 2
+#define FILE_LIST 3
+
+union VALUETYPE {
+ uint8_t b;
+ uint16_t h;
+ uint32_t l;
+ uint64_t q;
+ uint8_t hs[2]; /* 2 bytes of a fixed-endian "short" */
+ uint8_t hl[4]; /* 4 bytes of a fixed-endian "long" */
+ uint8_t hq[8]; /* 8 bytes of a fixed-endian "quad" */
+ char s[MAXstring]; /* the search string or regex pattern */
+ unsigned char us[MAXstring];
+ float f;
+ double d;
+};
+
+struct magic {
+ /* Word 1 */
+ uint16_t cont_level; /* level of ">" */
+ uint8_t flag;
+#define INDIR 0x01 /* if '(...)' appears */
+#define OFFADD 0x02 /* if '>&' or '>...(&' appears */
+#define INDIROFFADD 0x04 /* if '>&(' appears */
+#define UNSIGNED 0x08 /* comparison is unsigned */
+#define NOSPACE 0x10 /* suppress space character before output */
+#define BINTEST 0x20 /* test is for a binary type (set only
+ for top-level tests) */
+#define TEXTTEST 0x40 /* for passing to file_softmagic */
+
+ uint8_t factor;
+
+ /* Word 2 */
+ uint8_t reln; /* relation (0=eq, '>'=gt, etc) */
+ uint8_t vallen; /* length of string value, if any */
+ uint8_t type; /* comparison type (FILE_*) */
+ uint8_t in_type; /* type of indirection */
+#define FILE_INVALID 0
+#define FILE_BYTE 1
+#define FILE_SHORT 2
+#define FILE_DEFAULT 3
+#define FILE_LONG 4
+#define FILE_STRING 5
+#define FILE_DATE 6
+#define FILE_BESHORT 7
+#define FILE_BELONG 8
+#define FILE_BEDATE 9
+#define FILE_LESHORT 10
+#define FILE_LELONG 11
+#define FILE_LEDATE 12
+#define FILE_PSTRING 13
+#define FILE_LDATE 14
+#define FILE_BELDATE 15
+#define FILE_LELDATE 16
+#define FILE_REGEX 17
+#define FILE_BESTRING16 18
+#define FILE_LESTRING16 19
+#define FILE_SEARCH 20
+#define FILE_MEDATE 21
+#define FILE_MELDATE 22
+#define FILE_MELONG 23
+#define FILE_QUAD 24
+#define FILE_LEQUAD 25
+#define FILE_BEQUAD 26
+#define FILE_QDATE 27
+#define FILE_LEQDATE 28
+#define FILE_BEQDATE 29
+#define FILE_QLDATE 30
+#define FILE_LEQLDATE 31
+#define FILE_BEQLDATE 32
+#define FILE_FLOAT 33
+#define FILE_BEFLOAT 34
+#define FILE_LEFLOAT 35
+#define FILE_DOUBLE 36
+#define FILE_BEDOUBLE 37
+#define FILE_LEDOUBLE 38
+#define FILE_BEID3 39
+#define FILE_LEID3 40
+#define FILE_INDIRECT 41
+#define FILE_QWDATE 42
+#define FILE_LEQWDATE 43
+#define FILE_BEQWDATE 44
+#define FILE_NAME 45
+#define FILE_USE 46
+#define FILE_CLEAR 47
+#define FILE_DER 48
+#define FILE_NAMES_SIZE 49 /* size of array to contain all names */
+
+#define IS_STRING(t) \
+ ((t) == FILE_STRING || \
+ (t) == FILE_PSTRING || \
+ (t) == FILE_BESTRING16 || \
+ (t) == FILE_LESTRING16 || \
+ (t) == FILE_REGEX || \
+ (t) == FILE_SEARCH || \
+ (t) == FILE_INDIRECT || \
+ (t) == FILE_NAME || \
+ (t) == FILE_USE)
+
+#define FILE_FMT_NONE 0
+#define FILE_FMT_NUM 1 /* "cduxXi" */
+#define FILE_FMT_STR 2 /* "s" */
+#define FILE_FMT_QUAD 3 /* "ll" */
+#define FILE_FMT_FLOAT 4 /* "eEfFgG" */
+#define FILE_FMT_DOUBLE 5 /* "eEfFgG" */
+
+ /* Word 3 */
+ uint8_t in_op; /* operator for indirection */
+ uint8_t mask_op; /* operator for mask */
+#ifdef ENABLE_CONDITIONALS
+ uint8_t cond; /* conditional type */
+#else
+ uint8_t dummy;
+#endif
+ uint8_t factor_op;
+#define FILE_FACTOR_OP_PLUS '+'
+#define FILE_FACTOR_OP_MINUS '-'
+#define FILE_FACTOR_OP_TIMES '*'
+#define FILE_FACTOR_OP_DIV '/'
+#define FILE_FACTOR_OP_NONE '\0'
+
+#define FILE_OPS "&|^+-*/%"
+#define FILE_OPAND 0
+#define FILE_OPOR 1
+#define FILE_OPXOR 2
+#define FILE_OPADD 3
+#define FILE_OPMINUS 4
+#define FILE_OPMULTIPLY 5
+#define FILE_OPDIVIDE 6
+#define FILE_OPMODULO 7
+#define FILE_OPS_MASK 0x07 /* mask for above ops */
+#define FILE_UNUSED_1 0x08
+#define FILE_UNUSED_2 0x10
+#define FILE_OPSIGNED 0x20
+#define FILE_OPINVERSE 0x40
+#define FILE_OPINDIRECT 0x80
+
+#ifdef ENABLE_CONDITIONALS
+#define COND_NONE 0
+#define COND_IF 1
+#define COND_ELIF 2
+#define COND_ELSE 3
+#endif /* ENABLE_CONDITIONALS */
+
+ /* Word 4 */
+ uint32_t offset; /* offset to magic number */
+ /* Word 5 */
+ int32_t in_offset; /* offset from indirection */
+ /* Word 6 */
+ uint32_t lineno; /* line number in magic file */
+ /* Word 7,8 */
+ union {
+ uint64_t _mask; /* for use with numeric and date types */
+ struct {
+ uint32_t _count; /* repeat/line count */
+ uint32_t _flags; /* modifier flags */
+ } _s; /* for use with string types */
+ } _u;
+#define num_mask _u._mask
+#define str_range _u._s._count
+#define str_flags _u._s._flags
+ /* Words 9-24 */
+ union VALUETYPE value; /* either number or string */
+ /* Words 25-40 */
+ char desc[MAXDESC]; /* description */
+ /* Words 41-60 */
+ char mimetype[MAXMIME]; /* MIME type */
+ /* Words 61-62 */
+ char apple[8]; /* APPLE CREATOR/TYPE */
+ /* Words 63-78 */
+ char ext[64]; /* Popular extensions */
+};
+
+#define BIT(A) (1 << (A))
+#define STRING_COMPACT_WHITESPACE BIT(0)
+#define STRING_COMPACT_OPTIONAL_WHITESPACE BIT(1)
+#define STRING_IGNORE_LOWERCASE BIT(2)
+#define STRING_IGNORE_UPPERCASE BIT(3)
+#define REGEX_OFFSET_START BIT(4)
+#define STRING_TEXTTEST BIT(5)
+#define STRING_BINTEST BIT(6)
+#define PSTRING_1_BE BIT(7)
+#define PSTRING_1_LE BIT(7)
+#define PSTRING_2_BE BIT(8)
+#define PSTRING_2_LE BIT(9)
+#define PSTRING_4_BE BIT(10)
+#define PSTRING_4_LE BIT(11)
+#define REGEX_LINE_COUNT BIT(11)
+#define PSTRING_LEN \
+ (PSTRING_1_BE|PSTRING_2_LE|PSTRING_2_BE|PSTRING_4_LE|PSTRING_4_BE)
+#define PSTRING_LENGTH_INCLUDES_ITSELF BIT(12)
+#define STRING_TRIM BIT(13)
+#define CHAR_COMPACT_WHITESPACE 'W'
+#define CHAR_COMPACT_OPTIONAL_WHITESPACE 'w'
+#define CHAR_IGNORE_LOWERCASE 'c'
+#define CHAR_IGNORE_UPPERCASE 'C'
+#define CHAR_REGEX_OFFSET_START 's'
+#define CHAR_TEXTTEST 't'
+#define CHAR_TRIM 'T'
+#define CHAR_BINTEST 'b'
+#define CHAR_PSTRING_1_BE 'B'
+#define CHAR_PSTRING_1_LE 'B'
+#define CHAR_PSTRING_2_BE 'H'
+#define CHAR_PSTRING_2_LE 'h'
+#define CHAR_PSTRING_4_BE 'L'
+#define CHAR_PSTRING_4_LE 'l'
+#define CHAR_PSTRING_LENGTH_INCLUDES_ITSELF 'J'
+#define STRING_IGNORE_CASE (STRING_IGNORE_LOWERCASE|STRING_IGNORE_UPPERCASE)
+#define STRING_DEFAULT_RANGE 100
+
+#define INDIRECT_RELATIVE BIT(0)
+#define CHAR_INDIRECT_RELATIVE 'r'
+
+/* list of magic entries */
+struct mlist {
+ struct magic *magic; /* array of magic entries */
+ uint32_t nmagic; /* number of entries in array */
+ void *map; /* internal resources used by entry */
+ struct mlist *next, *prev;
+};
+
+#ifdef __cplusplus
+#define CAST(T, b) static_cast<T>(b)
+#define RCAST(T, b) reinterpret_cast<T>(b)
+#define CCAST(T, b) const_cast<T>(b)
+#else
+#define CAST(T, b) ((T)(b))
+#define RCAST(T, b) ((T)(b))
+#define CCAST(T, b) ((T)(uintptr_t)(b))
+#endif
+
+struct level_info {
+ int32_t off;
+ int got_match;
+#ifdef ENABLE_CONDITIONALS
+ int last_match;
+ int last_cond; /* used for error checking by parse() */
+#endif
+};
+
+#define MAGIC_SETS 2
+
+struct magic_set {
+ struct mlist *mlist[MAGIC_SETS]; /* list of regular entries */
+ struct cont {
+ size_t len;
+ struct level_info *li;
+ } c;
+ struct out {
+ char *buf; /* Accumulation buffer */
+ char *pbuf; /* Printable buffer */
+ } o;
+ uint32_t offset;
+ int error;
+ int flags; /* Control magic tests. */
+ int event_flags; /* Note things that happened. */
+#define EVENT_HAD_ERR 0x01
+ const char *file;
+ size_t line; /* current magic line number */
+
+ /* data for searches */
+ struct {
+ const char *s; /* start of search in original source */
+ size_t s_len; /* length of search region */
+ size_t offset; /* starting offset in source: XXX - should this be off_t? */
+ size_t rm_len; /* match length */
+ } search;
+
+ /* FIXME: Make the string dynamically allocated so that e.g.
+ strings matched in files can be longer than MAXstring */
+ union VALUETYPE ms_value; /* either number or string */
+ uint16_t indir_max;
+ uint16_t name_max;
+ uint16_t elf_shnum_max;
+ uint16_t elf_phnum_max;
+ uint16_t elf_notes_max;
+ uint16_t regex_max;
+ size_t bytes_max; /* number of bytes to read from file */
+#define FILE_INDIR_MAX 50
+#define FILE_NAME_MAX 30
+#define FILE_ELF_SHNUM_MAX 32768
+#define FILE_ELF_PHNUM_MAX 2048
+#define FILE_ELF_NOTES_MAX 256
+#define FILE_REGEX_MAX 8192
+};
+
+/* Type for Unicode characters */
+typedef unsigned long unichar;
+
+struct stat;
+#define FILE_T_LOCAL 1
+#define FILE_T_WINDOWS 2
+protected const char *file_fmttime(uint64_t, int, char *);
+protected struct magic_set *file_ms_alloc(int);
+protected void file_ms_free(struct magic_set *);
+protected int file_buffer(struct magic_set *, int, const char *, const void *,
+ size_t);
+protected int file_fsmagic(struct magic_set *, const char *, struct stat *);
+protected int file_pipe2file(struct magic_set *, int, const void *, size_t);
+protected int file_vprintf(struct magic_set *, const char *, va_list)
+ __attribute__((__format__(__printf__, 2, 0)));
+protected size_t file_printedlen(const struct magic_set *);
+protected int file_replace(struct magic_set *, const char *, const char *);
+protected int file_printf(struct magic_set *, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+protected int file_reset(struct magic_set *, int);
+protected int file_tryelf(struct magic_set *, int, const unsigned char *,
+ size_t);
+protected int file_trycdf(struct magic_set *, int, const unsigned char *,
+ size_t);
+#if HAVE_FORK
+protected int file_zmagic(struct magic_set *, int, const char *,
+ const unsigned char *, size_t);
+#endif
+protected int file_ascmagic(struct magic_set *, const unsigned char *, size_t,
+ int);
+protected int file_ascmagic_with_encoding(struct magic_set *,
+ const unsigned char *, size_t, unichar *, size_t, const char *,
+ const char *, int);
+protected int file_encoding(struct magic_set *, const unsigned char *, size_t,
+ unichar **, size_t *, const char **, const char **, const char **);
+protected int file_is_tar(struct magic_set *, const unsigned char *, size_t);
+protected int file_softmagic(struct magic_set *, const unsigned char *, size_t,
+ uint16_t *, uint16_t *, int, int);
+protected int file_apprentice(struct magic_set *, const char *, int);
+protected int buffer_apprentice(struct magic_set *, struct magic **,
+ size_t *, size_t);
+protected int file_magicfind(struct magic_set *, const char *, struct mlist *);
+protected uint64_t file_signextend(struct magic_set *, struct magic *,
+ uint64_t);
+protected void file_badread(struct magic_set *);
+protected void file_badseek(struct magic_set *);
+protected void file_oomem(struct magic_set *, size_t);
+protected void file_error(struct magic_set *, int, const char *, ...)
+ __attribute__((__format__(__printf__, 3, 4)));
+protected void file_magerror(struct magic_set *, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+protected void file_magwarn(struct magic_set *, const char *, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+protected void file_mdump(struct magic *);
+protected void file_showstr(FILE *, const char *, size_t);
+protected size_t file_mbswidth(const char *);
+protected const char *file_getbuffer(struct magic_set *);
+protected ssize_t sread(int, void *, size_t, int);
+protected int file_check_mem(struct magic_set *, unsigned int);
+protected int file_looks_utf8(const unsigned char *, size_t, unichar *,
+ size_t *);
+protected size_t file_pstring_length_size(const struct magic *);
+protected size_t file_pstring_get_length(const struct magic *, const char *);
+protected char * file_printable(char *, size_t, const char *);
+#ifdef __EMX__
+protected int file_os2_apptype(struct magic_set *, const char *, const void *,
+ size_t);
+#endif /* __EMX__ */
+
+#if defined(HAVE_LOCALE_H)
+#include <locale.h>
+#endif
+#if defined(HAVE_XLOCALE_H)
+#include <xlocale.h>
+#endif
+
+typedef struct {
+ const char *pat;
+#if defined(HAVE_NEWLOCALE) && defined(HAVE_USELOCALE) && defined(HAVE_FREELOCALE)
+#define USE_C_LOCALE
+ locale_t old_lc_ctype;
+ locale_t c_lc_ctype;
+#else
+ char *old_lc_ctype;
+#endif
+ int rc;
+ regex_t rx;
+} file_regex_t;
+
+protected int file_regcomp(file_regex_t *, const char *, int);
+protected int file_regexec(file_regex_t *, const char *, size_t, regmatch_t *,
+ int);
+protected void file_regfree(file_regex_t *);
+protected void file_regerror(file_regex_t *, int, struct magic_set *);
+
+typedef struct {
+ char *buf;
+ uint32_t offset;
+} file_pushbuf_t;
+
+protected file_pushbuf_t *file_push_buffer(struct magic_set *);
+protected char *file_pop_buffer(struct magic_set *, file_pushbuf_t *);
+
+#ifndef COMPILE_ONLY
+extern const char *file_names[];
+extern const size_t file_nnames;
+#endif
+
+#ifndef HAVE_STRERROR
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define strerror(e) \
+ (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
+#endif
+
+#ifndef HAVE_STRTOUL
+#define strtoul(a, b, c) strtol(a, b, c)
+#endif
+
+#ifndef HAVE_PREAD
+ssize_t pread(int, void *, size_t, off_t);
+#endif
+#ifndef HAVE_VASPRINTF
+int vasprintf(char **, const char *, va_list);
+#endif
+#ifndef HAVE_ASPRINTF
+int asprintf(char **, const char *, ...);
+#endif
+#ifndef HAVE_DPRINTF
+int dprintf(int, const char *, ...);
+#endif
+
+#ifndef HAVE_STRLCPY
+size_t strlcpy(char *, const char *, size_t);
+#endif
+#ifndef HAVE_STRLCAT
+size_t strlcat(char *, const char *, size_t);
+#endif
+#ifndef HAVE_STRCASESTR
+char *strcasestr(const char *, const char *);
+#endif
+#ifndef HAVE_GETLINE
+ssize_t getline(char **, size_t *, FILE *);
+ssize_t getdelim(char **, size_t *, int, FILE *);
+#endif
+#ifndef HAVE_CTIME_R
+char *ctime_r(const time_t *, char *);
+#endif
+#ifndef HAVE_ASCTIME_R
+char *asctime_r(const struct tm *, char *);
+#endif
+#ifndef HAVE_GMTIME_R
+struct tm *gmtime_r(const time_t *, struct tm *);
+#endif
+#ifndef HAVE_LOCALTIME_R
+struct tm *localtime_r(const time_t *, struct tm *);
+#endif
+#ifndef HAVE_FMTCHECK
+const char *fmtcheck(const char *, const char *)
+ __attribute__((__format_arg__(2)));
+#endif
+
+#if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK)
+#define QUICK
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifndef __cplusplus
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+#define FILE_RCSID(id) \
+static const char rcsid[] __attribute__((__used__)) = id;
+#else
+#define FILE_RCSID(id) \
+static const char *rcsid(const char *p) { \
+ return rcsid(p = id); \
+}
+#endif
+#else
+#define FILE_RCSID(id)
+#endif
+#ifndef __RCSID
+#define __RCSID(a)
+#endif
+
+#endif /* __file_h__ */
diff --git a/node_modules/mmmagic/deps/libmagic/src/file_opts.h b/node_modules/mmmagic/deps/libmagic/src/file_opts.h
new file mode 100644
index 0000000..52ace18
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/file_opts.h
@@ -0,0 +1,58 @@
+/*
+ * Table of command-line options
+ *
+ * The first column specifies the short name, if any, or 0 if none.
+ * The second column specifies the long name.
+ * The third column specifies whether it takes a parameter.
+ * The fourth column is the documentation.
+ *
+ * N.B. The long options' order must correspond to the code in file.c,
+ * and OPTSTRING must be kept up-to-date with the short options.
+ * Pay particular attention to the numbers of long-only options in the
+ * switch statement!
+ */
+
+OPT_LONGONLY("help", 0, 0, " display this help and exit\n", OPT_HELP)
+OPT('v', "version", 0, 0, " output version information and exit\n")
+OPT('m', "magic-file", 1, 0, " LIST use LIST as a colon-separated list of magic\n"
+ " number files\n")
+OPT('z', "uncompress", 0, 0, " try to look inside compressed files\n")
+OPT('Z', "uncompress-noreport", 0, 0, " only print the contents of compressed files\n")
+OPT('b', "brief", 0, 0, " do not prepend filenames to output lines\n")
+OPT('c', "checking-printout", 0, 0, " print the parsed form of the magic file, use in\n"
+ " conjunction with -m to debug a new magic file\n"
+ " before installing it\n")
+OPT('e', "exclude", 1, 0, " TEST exclude TEST from the list of test to be\n"
+ " performed for file. Valid tests are:\n"
+ " %o\n")
+OPT('f', "files-from", 1, 0, " FILE read the filenames to be examined from FILE\n")
+OPT('F', "separator", 1, 0, " STRING use string as separator instead of `:'\n")
+OPT('i', "mime", 0, 0, " output MIME type strings (--mime-type and\n"
+ " --mime-encoding)\n")
+OPT_LONGONLY("apple", 0, 0, " output the Apple CREATOR/TYPE\n", OPT_APPLE)
+OPT_LONGONLY("extension", 0, 0, " output a slash-separated list of extensions\n", OPT_EXTENSIONS)
+OPT_LONGONLY("mime-type", 0, 0, " output the MIME type\n", OPT_MIME_TYPE)
+OPT_LONGONLY("mime-encoding", 0, 0, " output the MIME encoding\n", OPT_MIME_ENCODING)
+OPT('k', "keep-going", 0, 0, " don't stop at the first match\n")
+OPT('l', "list", 0, 0, " list magic strength\n")
+#ifdef S_IFLNK
+OPT('L', "dereference", 0, 1, " follow symlinks")
+OPT('h', "no-dereference", 0, 2, " don't follow symlinks")
+#endif
+OPT('n', "no-buffer", 0, 0, " do not buffer output\n")
+OPT('N', "no-pad", 0, 0, " do not pad output\n")
+OPT('0', "print0", 0, 0, " terminate filenames with ASCII NUL\n")
+#if defined(HAVE_UTIME) || defined(HAVE_UTIMES)
+OPT('p', "preserve-date", 0, 0, " preserve access times on files\n")
+#endif
+OPT('P', "parameter", 1, 0, " set file engine parameter limits\n"
+ " indir 15 recursion limit for indirection\n"
+ " name 30 use limit for name/use magic\n"
+ " elf_notes 256 max ELF notes processed\n"
+ " elf_phnum 128 max ELF prog sections processed\n"
+ " elf_shnum 32768 max ELF sections processed\n")
+OPT('r', "raw", 0, 0, " don't translate unprintable chars to \\ooo\n")
+OPT('s', "special-files", 0, 0, " treat special (block/char devices) files as\n"
+ " ordinary ones\n")
+OPT('C', "compile", 0, 0, " compile file specified by -m\n")
+OPT('d', "debug", 0, 0, " print debugging messages\n")
diff --git a/node_modules/mmmagic/deps/libmagic/src/fmtcheck.c b/node_modules/mmmagic/deps/libmagic/src/fmtcheck.c
new file mode 100644
index 0000000..486aa08
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/fmtcheck.c
@@ -0,0 +1,251 @@
+/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code was contributed to The NetBSD Foundation by Allen Briggs.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+enum __e_fmtcheck_types {
+ FMTCHECK_START,
+ FMTCHECK_SHORT,
+ FMTCHECK_INT,
+ FMTCHECK_LONG,
+ FMTCHECK_QUAD,
+ FMTCHECK_SHORTPOINTER,
+ FMTCHECK_INTPOINTER,
+ FMTCHECK_LONGPOINTER,
+ FMTCHECK_QUADPOINTER,
+ FMTCHECK_DOUBLE,
+ FMTCHECK_LONGDOUBLE,
+ FMTCHECK_STRING,
+ FMTCHECK_WIDTH,
+ FMTCHECK_PRECISION,
+ FMTCHECK_DONE,
+ FMTCHECK_UNKNOWN
+};
+typedef enum __e_fmtcheck_types EFT;
+
+#define RETURN(pf,f,r) do { \
+ *(pf) = (f); \
+ return r; \
+ } /*NOTREACHED*/ /*CONSTCOND*/ while (0)
+
+static EFT
+get_next_format_from_precision(const char **pf)
+{
+ int sh, lg, quad, longdouble;
+ const char *f;
+
+ sh = lg = quad = longdouble = 0;
+
+ f = *pf;
+ switch (*f) {
+ case 'h':
+ f++;
+ sh = 1;
+ break;
+ case 'l':
+ f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == 'l') {
+ f++;
+ quad = 1;
+ } else {
+ lg = 1;
+ }
+ break;
+ case 'q':
+ f++;
+ quad = 1;
+ break;
+ case 'L':
+ f++;
+ longdouble = 1;
+ break;
+#ifdef WIN32
+ case 'I':
+ f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f == '3' && f[1] == '2') {
+ f += 2;
+ } else if (*f == '6' && f[1] == '4') {
+ f += 2;
+ quad = 1;
+ }
+#ifdef _WIN64
+ else {
+ quad = 1;
+ }
+#endif
+ break;
+#endif
+ default:
+ break;
+ }
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (strchr("diouxX", *f)) {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (lg)
+ RETURN(pf,f,FMTCHECK_LONG);
+ if (quad)
+ RETURN(pf,f,FMTCHECK_QUAD);
+ RETURN(pf,f,FMTCHECK_INT);
+ }
+ if (*f == 'n') {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (sh)
+ RETURN(pf,f,FMTCHECK_SHORTPOINTER);
+ if (lg)
+ RETURN(pf,f,FMTCHECK_LONGPOINTER);
+ if (quad)
+ RETURN(pf,f,FMTCHECK_QUADPOINTER);
+ RETURN(pf,f,FMTCHECK_INTPOINTER);
+ }
+ if (strchr("DOU", *f)) {
+ if (sh + lg + quad + longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_LONG);
+ }
+ if (strchr("eEfg", *f)) {
+ if (longdouble)
+ RETURN(pf,f,FMTCHECK_LONGDOUBLE);
+ if (sh + lg + quad)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_DOUBLE);
+ }
+ if (*f == 'c') {
+ if (sh + lg + quad + longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_INT);
+ }
+ if (*f == 's') {
+ if (sh + lg + quad + longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_STRING);
+ }
+ if (*f == 'p') {
+ if (sh + lg + quad + longdouble)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ RETURN(pf,f,FMTCHECK_LONG);
+ }
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ /*NOTREACHED*/
+}
+
+static EFT
+get_next_format_from_width(const char **pf)
+{
+ const char *f;
+
+ f = *pf;
+ if (*f == '.') {
+ f++;
+ if (*f == '*') {
+ RETURN(pf,f,FMTCHECK_PRECISION);
+ }
+ /* eat any precision (empty is allowed) */
+ while (isdigit((unsigned char)*f)) f++;
+ if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+ RETURN(pf,f,get_next_format_from_precision(pf));
+ /*NOTREACHED*/
+}
+
+static EFT
+get_next_format(const char **pf, EFT eft)
+{
+ int infmt;
+ const char *f;
+
+ if (eft == FMTCHECK_WIDTH) {
+ (*pf)++;
+ return get_next_format_from_width(pf);
+ } else if (eft == FMTCHECK_PRECISION) {
+ (*pf)++;
+ return get_next_format_from_precision(pf);
+ }
+
+ f = *pf;
+ infmt = 0;
+ while (!infmt) {
+ f = strchr(f, '%');
+ if (f == NULL)
+ RETURN(pf,f,FMTCHECK_DONE);
+ f++;
+ if (!*f)
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ if (*f != '%')
+ infmt = 1;
+ else
+ f++;
+ }
+
+ /* Eat any of the flags */
+ while (*f && (strchr("#0- +", *f)))
+ f++;
+
+ if (*f == '*') {
+ RETURN(pf,f,FMTCHECK_WIDTH);
+ }
+ /* eat any width */
+ while (isdigit((unsigned char)*f)) f++;
+ if (!*f) {
+ RETURN(pf,f,FMTCHECK_UNKNOWN);
+ }
+
+ RETURN(pf,f,get_next_format_from_width(pf));
+ /*NOTREACHED*/
+}
+
+const char *
+fmtcheck(const char *f1, const char *f2)
+{
+ const char *f1p, *f2p;
+ EFT f1t, f2t;
+
+ if (!f1) return f2;
+
+ f1p = f1;
+ f1t = FMTCHECK_START;
+ f2p = f2;
+ f2t = FMTCHECK_START;
+ while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
+ if (f1t == FMTCHECK_UNKNOWN)
+ return f2;
+ f2t = get_next_format(&f2p, f2t);
+ if (f1t != f2t)
+ return f2;
+ }
+ return f1;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/fsmagic.c b/node_modules/mmmagic/deps/libmagic/src/fsmagic.c
new file mode 100644
index 0000000..f84a10e
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/fsmagic.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * fsmagic - magic based on filesystem info - directory, special files, etc.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: fsmagic.c,v 1.77 2017/05/24 19:17:50 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+/* Since major is a function on SVR4, we cannot use `ifndef major'. */
+#ifdef MAJOR_IN_MKDEV
+# include <sys/mkdev.h>
+# define HAVE_MAJOR
+#endif
+#ifdef MAJOR_IN_SYSMACROS
+# include <sys/sysmacros.h>
+# define HAVE_MAJOR
+#endif
+#ifdef major /* Might be defined in sys/types.h. */
+# define HAVE_MAJOR
+#endif
+#ifdef WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+// XXX: change by mscdex
+# define S_IFIFO _S_IFIFO
+#endif
+
+#ifndef HAVE_MAJOR
+# define major(dev) (((dev) >> 8) & 0xff)
+# define minor(dev) ((dev) & 0xff)
+#endif
+#undef HAVE_MAJOR
+#ifdef S_IFLNK
+private int
+bad_link(struct magic_set *ms, int err, char *buf)
+{
+ int mime = ms->flags & MAGIC_MIME;
+ if ((mime & MAGIC_MIME_TYPE) &&
+ file_printf(ms, "inode/symlink")
+ == -1)
+ return -1;
+ else if (!mime) {
+ if (ms->flags & MAGIC_ERROR) {
+ file_error(ms, err,
+ "broken symbolic link to %s", buf);
+ return -1;
+ }
+ if (file_printf(ms, "broken symbolic link to %s", buf) == -1)
+ return -1;
+ }
+ return 1;
+}
+#endif
+private int
+handle_mime(struct magic_set *ms, int mime, const char *str)
+{
+ if ((mime & MAGIC_MIME_TYPE)) {
+ if (file_printf(ms, "inode/%s", str) == -1)
+ return -1;
+ if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms,
+ "; charset=") == -1)
+ return -1;
+ }
+ if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms, "binary") == -1)
+ return -1;
+ return 0;
+}
+
+protected int
+file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
+{
+ int ret, did = 0;
+ int mime = ms->flags & MAGIC_MIME;
+ int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION);
+#ifdef S_IFLNK
+ char buf[BUFSIZ+4];
+ ssize_t nch;
+ struct stat tstatbuf;
+#endif
+
+ if (fn == NULL)
+ return 0;
+
+#define COMMA (did++ ? ", " : "")
+ /*
+ * Fstat is cheaper but fails for files you don't have read perms on.
+ * On 4.2BSD and similar systems, use lstat() to identify symlinks.
+ */
+#ifdef S_IFLNK
+ if ((ms->flags & MAGIC_SYMLINK) == 0)
+ ret = lstat(fn, sb);
+ else
+#endif
+ ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
+
+#ifdef WIN32
+ {
+ HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE |
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
+ NULL);
+ if (hFile != INVALID_HANDLE_VALUE) {
+ /*
+ * Stat failed, but we can still open it - assume it's
+ * a block device, if nothing else.
+ */
+ if (ret) {
+ sb->st_mode = S_IFBLK;
+ ret = 0;
+ }
+ switch (GetFileType(hFile)) {
+ case FILE_TYPE_CHAR:
+ sb->st_mode |= S_IFCHR;
+ sb->st_mode &= ~S_IFREG;
+ break;
+ case FILE_TYPE_PIPE:
+ sb->st_mode |= S_IFIFO;
+ sb->st_mode &= ~S_IFREG;
+ break;
+ }
+ CloseHandle(hFile);
+ }
+ }
+#endif
+
+ if (ret) {
+ if (ms->flags & MAGIC_ERROR) {
+ file_error(ms, errno, "cannot stat `%s'", fn);
+ return -1;
+ }
+ if (file_printf(ms, "cannot open `%s' (%s)",
+ fn, strerror(errno)) == -1)
+ return -1;
+ return 0;
+ }
+
+ ret = 1;
+ if (!mime && !silent) {
+#ifdef S_ISUID
+ if (sb->st_mode & S_ISUID)
+ if (file_printf(ms, "%ssetuid", COMMA) == -1)
+ return -1;
+#endif
+#ifdef S_ISGID
+ if (sb->st_mode & S_ISGID)
+ if (file_printf(ms, "%ssetgid", COMMA) == -1)
+ return -1;
+#endif
+#ifdef S_ISVTX
+ if (sb->st_mode & S_ISVTX)
+ if (file_printf(ms, "%ssticky", COMMA) == -1)
+ return -1;
+#endif
+ }
+
+ switch (sb->st_mode & S_IFMT) {
+ case S_IFDIR:
+ if (mime) {
+ if (handle_mime(ms, mime, "directory") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%sdirectory", COMMA) == -1)
+ return -1;
+ break;
+#ifdef S_IFCHR
+ case S_IFCHR:
+ /*
+ * If -s has been specified, treat character special files
+ * like ordinary files. Otherwise, just report that they
+ * are block special files and go on to the next file.
+ */
+ if ((ms->flags & MAGIC_DEVICES) != 0) {
+ ret = 0;
+ break;
+ }
+ if (mime) {
+ if (handle_mime(ms, mime, "chardevice") == -1)
+ return -1;
+ } else if (silent) {
+ } else {
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+# ifdef dv_unit
+ if (file_printf(ms, "%scharacter special (%d/%d/%d)",
+ COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
+ dv_subunit(sb->st_rdev)) == -1)
+ return -1;
+# else
+ if (file_printf(ms, "%scharacter special (%ld/%ld)",
+ COMMA, (long)major(sb->st_rdev),
+ (long)minor(sb->st_rdev)) == -1)
+ return -1;
+# endif
+#else
+ if (file_printf(ms, "%scharacter special", COMMA) == -1)
+ return -1;
+#endif
+ }
+ break;
+#endif
+#ifdef S_IFBLK
+ case S_IFBLK:
+ /*
+ * If -s has been specified, treat block special files
+ * like ordinary files. Otherwise, just report that they
+ * are block special files and go on to the next file.
+ */
+ if ((ms->flags & MAGIC_DEVICES) != 0) {
+ ret = 0;
+ break;
+ }
+ if (mime) {
+ if (handle_mime(ms, mime, "blockdevice") == -1)
+ return -1;
+ } else if (silent) {
+ } else {
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+# ifdef dv_unit
+ if (file_printf(ms, "%sblock special (%d/%d/%d)",
+ COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
+ dv_subunit(sb->st_rdev)) == -1)
+ return -1;
+# else
+ if (file_printf(ms, "%sblock special (%ld/%ld)",
+ COMMA, (long)major(sb->st_rdev),
+ (long)minor(sb->st_rdev)) == -1)
+ return -1;
+# endif
+#else
+ if (file_printf(ms, "%sblock special", COMMA) == -1)
+ return -1;
+#endif
+ }
+ break;
+#endif
+ /* TODO add code to handle V7 MUX and Blit MUX files */
+#ifdef S_IFIFO
+ case S_IFIFO:
+ if((ms->flags & MAGIC_DEVICES) != 0)
+ break;
+ if (mime) {
+ if (handle_mime(ms, mime, "fifo") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%sfifo (named pipe)", COMMA) == -1)
+ return -1;
+ break;
+#endif
+#ifdef S_IFDOOR
+ case S_IFDOOR:
+ if (mime) {
+ if (handle_mime(ms, mime, "door") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%sdoor", COMMA) == -1)
+ return -1;
+ break;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
+ if (ms->flags & MAGIC_ERROR) {
+ file_error(ms, errno, "unreadable symlink `%s'",
+ fn);
+ return -1;
+ }
+ if (mime) {
+ if (handle_mime(ms, mime, "symlink") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms,
+ "%sunreadable symlink `%s' (%s)", COMMA, fn,
+ strerror(errno)) == -1)
+ return -1;
+ break;
+ }
+ buf[nch] = '\0'; /* readlink(2) does not do this */
+
+ /* If broken symlink, say so and quit early. */
+ if (*buf == '/') {
+ if (stat(buf, &tstatbuf) < 0)
+ return bad_link(ms, errno, buf);
+ } else {
+ char *tmp;
+ char buf2[BUFSIZ+BUFSIZ+4];
+
+ if ((tmp = strrchr(fn, '/')) == NULL) {
+ tmp = buf; /* in current directory anyway */
+ } else {
+ if (tmp - fn + 1 > BUFSIZ) {
+ if (ms->flags & MAGIC_ERROR) {
+ file_error(ms, 0,
+ "path too long: `%s'", buf);
+ return -1;
+ }
+ if (mime) {
+ if (handle_mime(ms, mime,
+ "x-path-too-long") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms,
+ "%spath too long: `%s'", COMMA,
+ fn) == -1)
+ return -1;
+ break;
+ }
+ /* take dir part */
+ (void)strlcpy(buf2, fn, sizeof buf2);
+ buf2[tmp - fn + 1] = '\0';
+ /* plus (rel) link */
+ (void)strlcat(buf2, buf, sizeof buf2);
+ tmp = buf2;
+ }
+ if (stat(tmp, &tstatbuf) < 0)
+ return bad_link(ms, errno, buf);
+ }
+
+ /* Otherwise, handle it. */
+ if ((ms->flags & MAGIC_SYMLINK) != 0) {
+ const char *p;
+ ms->flags &= MAGIC_SYMLINK;
+ p = magic_file(ms, buf);
+ ms->flags |= MAGIC_SYMLINK;
+ if (p == NULL)
+ return -1;
+ } else { /* just print what it points to */
+ if (mime) {
+ if (handle_mime(ms, mime, "symlink") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%ssymbolic link to %s",
+ COMMA, buf) == -1)
+ return -1;
+ }
+ break;
+#endif
+#ifdef S_IFSOCK
+#ifndef __COHERENT__
+ case S_IFSOCK:
+ if (mime) {
+ if (handle_mime(ms, mime, "socket") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%ssocket", COMMA) == -1)
+ return -1;
+ break;
+#endif
+#endif
+ case S_IFREG:
+ /*
+ * regular file, check next possibility
+ *
+ * If stat() tells us the file has zero length, report here that
+ * the file is empty, so we can skip all the work of opening and
+ * reading the file.
+ * But if the -s option has been given, we skip this
+ * optimization, since on some systems, stat() reports zero
+ * size for raw disk partitions. (If the block special device
+ * really has zero length, the fact that it is empty will be
+ * detected and reported correctly when we read the file.)
+ */
+ if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
+ if (mime) {
+ if (handle_mime(ms, mime, "x-empty") == -1)
+ return -1;
+ } else if (silent) {
+ } else if (file_printf(ms, "%sempty", COMMA) == -1)
+ return -1;
+ break;
+ }
+ ret = 0;
+ break;
+
+ default:
+ file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
+ return -1;
+ /*NOTREACHED*/
+ }
+
+ if (!silent && !mime && did && ret == 0) {
+ if (file_printf(ms, " ") == -1)
+ return -1;
+ }
+ return ret;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/funcs.c b/node_modules/mmmagic/deps/libmagic/src/funcs.c
new file mode 100644
index 0000000..d7a18f4
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/funcs.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) Christos Zoulas 2003.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: funcs.c,v 1.93 2017/08/28 13:39:18 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#if defined(HAVE_WCHAR_H)
+#include <wchar.h>
+#endif
+#if defined(HAVE_WCTYPE_H)
+#include <wctype.h>
+#endif
+#if defined(HAVE_LIMITS_H)
+#include <limits.h>
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)~0)
+#endif
+
+/*
+ * Like printf, only we append to a buffer.
+ */
+protected int
+file_vprintf(struct magic_set *ms, const char *fmt, va_list ap)
+{
+ int len;
+ char *buf, *newstr;
+
+ if (ms->event_flags & EVENT_HAD_ERR)
+ return 0;
+ len = vasprintf(&buf, fmt, ap);
+ if (len < 0)
+ goto out;
+
+ if (ms->o.buf != NULL) {
+ len = asprintf(&newstr, "%s%s", ms->o.buf, buf);
+ free(buf);
+ if (len < 0)
+ goto out;
+ free(ms->o.buf);
+ buf = newstr;
+ }
+ ms->o.buf = buf;
+ return 0;
+out:
+ fprintf(stderr, "vasprintf failed (%s)", strerror(errno));
+ return -1;
+}
+
+protected int
+file_printf(struct magic_set *ms, const char *fmt, ...)
+{
+ int rv;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rv = file_vprintf(ms, fmt, ap);
+ va_end(ap);
+ return rv;
+}
+
+/*
+ * error - print best error message possible
+ */
+/*VARARGS*/
+__attribute__((__format__(__printf__, 3, 0)))
+private void
+file_error_core(struct magic_set *ms, int error, const char *f, va_list va,
+ size_t lineno)
+{
+ /* Only the first error is ok */
+ if (ms->event_flags & EVENT_HAD_ERR)
+ return;
+ if (lineno != 0) {
+ free(ms->o.buf);
+ ms->o.buf = NULL;
+ file_printf(ms, "line %" SIZE_T_FORMAT "u:", lineno);
+ }
+ if (ms->o.buf && *ms->o.buf)
+ file_printf(ms, " ");
+ file_vprintf(ms, f, va);
+ if (error > 0)
+ file_printf(ms, " (%s)", strerror(error));
+ ms->event_flags |= EVENT_HAD_ERR;
+ ms->error = error;
+}
+
+/*VARARGS*/
+protected void
+file_error(struct magic_set *ms, int error, const char *f, ...)
+{
+ va_list va;
+ va_start(va, f);
+ file_error_core(ms, error, f, va, 0);
+ va_end(va);
+}
+
+/*
+ * Print an error with magic line number.
+ */
+/*VARARGS*/
+protected void
+file_magerror(struct magic_set *ms, const char *f, ...)
+{
+ va_list va;
+ va_start(va, f);
+ file_error_core(ms, 0, f, va, ms->line);
+ va_end(va);
+}
+
+protected void
+file_oomem(struct magic_set *ms, size_t len)
+{
+ file_error(ms, errno, "cannot allocate %" SIZE_T_FORMAT "u bytes",
+ len);
+}
+
+protected void
+file_badseek(struct magic_set *ms)
+{
+ file_error(ms, errno, "error seeking");
+}
+
+protected void
+file_badread(struct magic_set *ms)
+{
+ file_error(ms, errno, "error reading");
+}
+
+#ifndef COMPILE_ONLY
+
+static int
+checkdone(struct magic_set *ms, int *rv)
+{
+ if ((ms->flags & MAGIC_CONTINUE) == 0)
+ return 1;
+ if (file_printf(ms, "\n- ") == -1)
+ *rv = -1;
+ return 0;
+}
+
+/*ARGSUSED*/
+protected int
+file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__unused__)),
+ const void *buf, size_t nb)
+{
+ int m = 0, rv = 0, looks_text = 0;
+ const unsigned char *ubuf = CAST(const unsigned char *, buf);
+ unichar *u8buf = NULL;
+ size_t ulen;
+ const char *code = NULL;
+ const char *code_mime = "binary";
+ const char *type = "application/octet-stream";
+ const char *def = "data";
+ const char *ftype = NULL;
+
+ if (nb == 0) {
+ def = "empty";
+ type = "application/x-empty";
+ goto simple;
+ } else if (nb == 1) {
+ def = "very short file (no magic)";
+ goto simple;
+ }
+
+ if ((ms->flags & MAGIC_NO_CHECK_ENCODING) == 0) {
+ looks_text = file_encoding(ms, ubuf, nb, &u8buf, &ulen,
+ &code, &code_mime, &ftype);
+ }
+
+#ifdef __EMX__
+ if ((ms->flags & MAGIC_NO_CHECK_APPTYPE) == 0 && inname) {
+ m = file_os2_apptype(ms, inname, buf, nb);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try os2_apptype %d]\n", m);
+ switch (m) {
+ case -1:
+ return -1;
+ case 0:
+ break;
+ default:
+ return 1;
+ }
+ }
+#endif
+#if HAVE_FORK
+ /* try compression stuff */
+ if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) {
+ m = file_zmagic(ms, fd, inname, ubuf, nb);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try zmagic %d]\n", m);
+ if (m) {
+ goto done_encoding;
+ }
+ }
+#endif
+ /* Check if we have a tar file */
+ if ((ms->flags & MAGIC_NO_CHECK_TAR) == 0) {
+ m = file_is_tar(ms, ubuf, nb);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try tar %d]\n", m);
+ if (m) {
+ if (checkdone(ms, &rv))
+ goto done;
+ }
+ }
+
+ /* Check if we have a CDF file */
+ if ((ms->flags & MAGIC_NO_CHECK_CDF) == 0) {
+ m = file_trycdf(ms, fd, ubuf, nb);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try cdf %d]\n", m);
+ if (m) {
+ if (checkdone(ms, &rv))
+ goto done;
+ }
+ }
+
+ /* try soft magic tests */
+ if ((ms->flags & MAGIC_NO_CHECK_SOFT) == 0) {
+ m = file_softmagic(ms, ubuf, nb, NULL, NULL, BINTEST,
+ looks_text);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try softmagic %d]\n", m);
+ if (m) {
+#ifdef BUILTIN_ELF
+ if ((ms->flags & MAGIC_NO_CHECK_ELF) == 0 && m == 1 &&
+ nb > 5 && fd != -1) {
+ /*
+ * We matched something in the file, so this
+ * *might* be an ELF file, and the file is at
+ * least 5 bytes long, so if it's an ELF file
+ * it has at least one byte past the ELF magic
+ * number - try extracting information from the
+ * ELF headers that cannot easily * be
+ * extracted with rules in the magic file.
+ */
+ m = file_tryelf(ms, fd, ubuf, nb);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try elf %d]\n",
+ m);
+ }
+#endif
+ if (checkdone(ms, &rv))
+ goto done;
+ }
+ }
+
+ /* try text properties */
+ if ((ms->flags & MAGIC_NO_CHECK_TEXT) == 0) {
+
+ m = file_ascmagic(ms, ubuf, nb, looks_text);
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void)fprintf(stderr, "[try ascmagic %d]\n", m);
+ if (m) {
+ if (checkdone(ms, &rv))
+ goto done;
+ }
+ }
+
+simple:
+ /* give up */
+ m = 1;
+ if (ms->flags & MAGIC_MIME) {
+ if ((ms->flags & MAGIC_MIME_TYPE) &&
+ file_printf(ms, "%s", type) == -1)
+ rv = -1;
+ } else if (ms->flags & MAGIC_APPLE) {
+ if (file_printf(ms, "UNKNUNKN") == -1)
+ rv = -1;
+ } else if (ms->flags & MAGIC_EXTENSION) {
+ if (file_printf(ms, "???") == -1)
+ rv = -1;
+ } else {
+ if (file_printf(ms, "%s", def) == -1)
+ rv = -1;
+ }
+ done:
+ if ((ms->flags & MAGIC_MIME_ENCODING) != 0) {
+ if (ms->flags & MAGIC_MIME_TYPE)
+ if (file_printf(ms, "; charset=") == -1)
+ rv = -1;
+ if (file_printf(ms, "%s", code_mime) == -1)
+ rv = -1;
+ }
+#if HAVE_FORK
+ done_encoding:
+#endif
+ free(u8buf);
+ if (rv)
+ return rv;
+
+ return m;
+}
+#endif
+
+protected int
+file_reset(struct magic_set *ms, int checkloaded)
+{
+ if (checkloaded && ms->mlist[0] == NULL) {
+ file_error(ms, 0, "no magic files loaded");
+ return -1;
+ }
+ if (ms->o.buf) {
+ free(ms->o.buf);
+ ms->o.buf = NULL;
+ }
+ if (ms->o.pbuf) {
+ free(ms->o.pbuf);
+ ms->o.pbuf = NULL;
+ }
+ ms->event_flags &= ~EVENT_HAD_ERR;
+ ms->error = -1;
+ return 0;
+}
+
+#define OCTALIFY(n, o) \
+ /*LINTED*/ \
+ (void)(*(n)++ = '\\', \
+ *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
+ *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
+ *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
+ (o)++)
+
+protected const char *
+file_getbuffer(struct magic_set *ms)
+{
+ char *pbuf, *op, *np;
+ size_t psize, len;
+
+ if (ms->event_flags & EVENT_HAD_ERR)
+ return NULL;
+
+ if (ms->flags & MAGIC_RAW)
+ return ms->o.buf;
+
+ if (ms->o.buf == NULL)
+ return NULL;
+
+ /* * 4 is for octal representation, + 1 is for NUL */
+ len = strlen(ms->o.buf);
+ if (len > (SIZE_MAX - 1) / 4) {
+ file_oomem(ms, len);
+ return NULL;
+ }
+ psize = len * 4 + 1;
+ if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) {
+ file_oomem(ms, psize);
+ return NULL;
+ }
+ ms->o.pbuf = pbuf;
+
+#if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
+ {
+ mbstate_t state;
+ wchar_t nextchar;
+ int mb_conv = 1;
+ size_t bytesconsumed;
+ char *eop;
+ (void)memset(&state, 0, sizeof(mbstate_t));
+
+ np = ms->o.pbuf;
+ op = ms->o.buf;
+ eop = op + len;
+
+ while (op < eop) {
+ bytesconsumed = mbrtowc(&nextchar, op,
+ (size_t)(eop - op), &state);
+ if (bytesconsumed == (size_t)(-1) ||
+ bytesconsumed == (size_t)(-2)) {
+ mb_conv = 0;
+ break;
+ }
+
+ if (iswprint(nextchar)) {
+ (void)memcpy(np, op, bytesconsumed);
+ op += bytesconsumed;
+ np += bytesconsumed;
+ } else {
+ while (bytesconsumed-- > 0)
+ OCTALIFY(np, op);
+ }
+ }
+ *np = '\0';
+
+ /* Parsing succeeded as a multi-byte sequence */
+ if (mb_conv != 0)
+ return ms->o.pbuf;
+ }
+#endif
+
+ for (np = ms->o.pbuf, op = ms->o.buf; *op;) {
+ if (isprint((unsigned char)*op)) {
+ *np++ = *op++;
+ } else {
+ OCTALIFY(np, op);
+ }
+ }
+ *np = '\0';
+ return ms->o.pbuf;
+}
+
+protected int
+file_check_mem(struct magic_set *ms, unsigned int level)
+{
+ size_t len;
+
+ if (level >= ms->c.len) {
+ len = (ms->c.len = 20 + level) * sizeof(*ms->c.li);
+ ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ?
+ malloc(len) :
+ realloc(ms->c.li, len));
+ if (ms->c.li == NULL) {
+ file_oomem(ms, len);
+ return -1;
+ }
+ }
+ ms->c.li[level].got_match = 0;
+#ifdef ENABLE_CONDITIONALS
+ ms->c.li[level].last_match = 0;
+ ms->c.li[level].last_cond = COND_NONE;
+#endif /* ENABLE_CONDITIONALS */
+ return 0;
+}
+
+protected size_t
+file_printedlen(const struct magic_set *ms)
+{
+ return ms->o.buf == NULL ? 0 : strlen(ms->o.buf);
+}
+
+protected int
+file_replace(struct magic_set *ms, const char *pat, const char *rep)
+{
+ file_regex_t rx;
+ int rc, rv = -1;
+
+ rc = file_regcomp(&rx, pat, REG_EXTENDED);
+ if (rc) {
+ file_regerror(&rx, rc, ms);
+ } else {
+ regmatch_t rm;
+ int nm = 0;
+ while (file_regexec(&rx, ms->o.buf, 1, &rm, 0) == 0) {
+ ms->o.buf[rm.rm_so] = '\0';
+ if (file_printf(ms, "%s%s", rep,
+ rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1)
+ goto out;
+ nm++;
+ }
+ rv = nm;
+ }
+out:
+ file_regfree(&rx);
+ return rv;
+}
+
+protected int
+file_regcomp(file_regex_t *rx, const char *pat, int flags)
+{
+#ifdef USE_C_LOCALE
+ rx->c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
+ assert(rx->c_lc_ctype != NULL);
+ rx->old_lc_ctype = uselocale(rx->c_lc_ctype);
+ assert(rx->old_lc_ctype != NULL);
+#else
+ rx->old_lc_ctype = setlocale(LC_CTYPE, "C");
+#endif
+ rx->pat = pat;
+
+ return rx->rc = regcomp(&rx->rx, pat, flags);
+}
+
+protected int
+file_regexec(file_regex_t *rx, const char *str, size_t nmatch,
+ regmatch_t* pmatch, int eflags)
+{
+ assert(rx->rc == 0);
+ /* XXX: force initialization because glibc does not always do this */
+ memset(pmatch, 0, nmatch * sizeof(*pmatch));
+ return regexec(&rx->rx, str, nmatch, pmatch, eflags);
+}
+
+protected void
+file_regfree(file_regex_t *rx)
+{
+ if (rx->rc == 0)
+ regfree(&rx->rx);
+#ifdef USE_C_LOCALE
+ (void)uselocale(rx->old_lc_ctype);
+ freelocale(rx->c_lc_ctype);
+#else
+ (void)setlocale(LC_CTYPE, rx->old_lc_ctype);
+#endif
+}
+
+protected void
+file_regerror(file_regex_t *rx, int rc, struct magic_set *ms)
+{
+ char errmsg[512];
+
+ (void)regerror(rc, &rx->rx, errmsg, sizeof(errmsg));
+ file_magerror(ms, "regex error %d for `%s', (%s)", rc, rx->pat,
+ errmsg);
+}
+
+protected file_pushbuf_t *
+file_push_buffer(struct magic_set *ms)
+{
+ file_pushbuf_t *pb;
+
+ if (ms->event_flags & EVENT_HAD_ERR)
+ return NULL;
+
+ if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL)
+ return NULL;
+
+ pb->buf = ms->o.buf;
+ pb->offset = ms->offset;
+
+ ms->o.buf = NULL;
+ ms->offset = 0;
+
+ return pb;
+}
+
+protected char *
+file_pop_buffer(struct magic_set *ms, file_pushbuf_t *pb)
+{
+ char *rbuf;
+
+ if (ms->event_flags & EVENT_HAD_ERR) {
+ free(pb->buf);
+ free(pb);
+ return NULL;
+ }
+
+ rbuf = ms->o.buf;
+
+ ms->o.buf = pb->buf;
+ ms->offset = pb->offset;
+
+ free(pb);
+ return rbuf;
+}
+
+/*
+ * convert string to ascii printable format.
+ */
+protected char *
+file_printable(char *buf, size_t bufsiz, const char *str)
+{
+ char *ptr, *eptr;
+ const unsigned char *s = (const unsigned char *)str;
+
+ for (ptr = buf, eptr = ptr + bufsiz - 1; ptr < eptr && *s; s++) {
+ if (isprint(*s)) {
+ *ptr++ = *s;
+ continue;
+ }
+ if (ptr >= eptr - 3)
+ break;
+ *ptr++ = '\\';
+ *ptr++ = ((CAST(unsigned int, *s) >> 6) & 7) + '0';
+ *ptr++ = ((CAST(unsigned int, *s) >> 3) & 7) + '0';
+ *ptr++ = ((CAST(unsigned int, *s) >> 0) & 7) + '0';
+ }
+ *ptr = '\0';
+ return buf;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/getline.c b/node_modules/mmmagic/deps/libmagic/src/getline.c
new file mode 100644
index 0000000..67bd006
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/getline.c
@@ -0,0 +1,107 @@
+/* $NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file.h"
+#if !HAVE_GETLINE
+#include <stdlib.h>
+#include <stdio.h>
+// XXX: change by mscdex
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+public ssize_t
+getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
+{
+ char *ptr, *eptr;
+
+
+ if (*buf == NULL || *bufsiz == 0) {
+ *bufsiz = BUFSIZ;
+ if ((*buf = malloc(*bufsiz)) == NULL)
+ return -1;
+ }
+
+ for (ptr = *buf, eptr = *buf + *bufsiz;;) {
+ int c = fgetc(fp);
+ if (c == -1) {
+ if (feof(fp)) {
+ ssize_t diff = (ssize_t)(ptr - *buf);
+ if (diff != 0) {
+ *ptr = '\0';
+ return diff;
+ }
+ }
+ return -1;
+ }
+ *ptr++ = c;
+ if (c == delimiter) {
+ *ptr = '\0';
+ return ptr - *buf;
+ }
+ if (ptr + 2 >= eptr) {
+ char *nbuf;
+ size_t nbufsiz = *bufsiz * 2;
+ ssize_t d = ptr - *buf;
+ if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
+ return -1;
+ *buf = nbuf;
+ *bufsiz = nbufsiz;
+ eptr = nbuf + nbufsiz;
+ ptr = nbuf + d;
+ }
+ }
+}
+
+public ssize_t
+getline(char **buf, size_t *bufsiz, FILE *fp)
+{
+ return getdelim(buf, bufsiz, '\n', fp);
+}
+
+#endif
+
+#ifdef TEST
+int
+main(int argc, char *argv[])
+{
+ char *p = NULL;
+ ssize_t len;
+ size_t n = 0;
+
+ while ((len = getline(&p, &n, stdin)) != -1)
+ (void)printf("%" SIZE_T_FORMAT "d %s", len, p);
+ free(p);
+ return 0;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/getopt_long.c b/node_modules/mmmagic/deps/libmagic/src/getopt_long.c
new file mode 100644
index 0000000..d357dc3
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/getopt_long.c
@@ -0,0 +1,498 @@
+/* $NetBSD: getopt_long.c,v 1.21.4.1 2008/01/09 01:34:14 matt Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: getopt_long.c,v 1.6 2009/02/13 18:48:05 christos Exp $")
+#endif /* lint */
+
+#include <assert.h>
+#ifdef HAVE_ERR_H
+#include <err.h>
+#else
+#define warnx printf
+#endif
+#include <errno.h>
+#if defined(HAVE_GETOPT_H) && defined(HAVE_STRUCT_OPTION)
+#include <getopt.h>
+#else
+#include "mygetopt.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#define REPLACE_GETOPT
+
+#ifndef _DIAGASSERT
+#define _DIAGASSERT assert
+#endif
+
+#ifdef REPLACE_GETOPT
+#ifdef __weak_alias
+__weak_alias(getopt,_getopt)
+#endif
+int opterr = 1; /* if error message should be printed */
+int optind = 1; /* index into parent argv vector */
+int optopt = '?'; /* character checked for validity */
+int optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+#elif HAVE_NBTOOL_CONFIG_H && !HAVE_DECL_OPTRESET
+static int optreset;
+#endif
+
+#ifdef __weak_alias
+__weak_alias(getopt_long,_getopt_long)
+#endif
+
+#define IGNORE_FIRST (*options == '-' || *options == '+')
+#define PRINT_ERROR ((opterr) && ((*options != ':') \
+ || (IGNORE_FIRST && options[1] != ':')))
+#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
+#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
+/* XXX: GNU ignores PC if *options == '-' */
+#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
+
+/* return values */
+#define BADCH (int)'?'
+#define BADARG ((IGNORE_FIRST && options[1] == ':') \
+ || (*options == ':') ? (int)':' : (int)'?')
+#define INORDER (int)1
+
+#define EMSG ""
+
+static int getopt_internal(int, char **, const char *);
+static int gcd(int, int);
+static void permute_args(int, int, int, char **);
+
+static const char *place = EMSG; /* option letter processing */
+
+/* XXX: set optreset to 1 rather than these two */
+static int nonopt_start = -1; /* first non option argument (for permute) */
+static int nonopt_end = -1; /* first option after non options (for permute) */
+
+/* Error messages */
+static const char recargchar[] = "option requires an argument -- %c";
+static const char recargstring[] = "option requires an argument -- %s";
+static const char ambig[] = "ambiguous option -- %.*s";
+static const char noarg[] = "option doesn't take an argument -- %.*s";
+static const char illoptchar[] = "unknown option -- %c";
+static const char illoptstring[] = "unknown option -- %s";
+
+
+/*
+ * Compute the greatest common divisor of a and b.
+ */
+static int
+gcd(a, b)
+ int a;
+ int b;
+{
+ int c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return b;
+}
+
+/*
+ * Exchange the block from nonopt_start to nonopt_end with the block
+ * from nonopt_end to opt_end (keeping the same order of arguments
+ * in each block).
+ */
+static void
+permute_args(panonopt_start, panonopt_end, opt_end, nargv)
+ int panonopt_start;
+ int panonopt_end;
+ int opt_end;
+ char **nargv;
+{
+ int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
+ char *swap;
+
+ _DIAGASSERT(nargv != NULL);
+
+ /*
+ * compute lengths of blocks and number and size of cycles
+ */
+ nnonopts = panonopt_end - panonopt_start;
+ nopts = opt_end - panonopt_end;
+ ncycle = gcd(nnonopts, nopts);
+ cyclelen = (opt_end - panonopt_start) / ncycle;
+
+ for (i = 0; i < ncycle; i++) {
+ cstart = panonopt_end+i;
+ pos = cstart;
+ for (j = 0; j < cyclelen; j++) {
+ if (pos >= panonopt_end)
+ pos -= nnonopts;
+ else
+ pos += nopts;
+ swap = nargv[pos];
+ nargv[pos] = nargv[cstart];
+ nargv[cstart] = swap;
+ }
+ }
+}
+
+/*
+ * getopt_internal --
+ * Parse argc/argv argument vector. Called by user level routines.
+ * Returns -2 if -- is found (can be long option or end of options marker).
+ */
+static int
+getopt_internal(nargc, nargv, options)
+ int nargc;
+ char **nargv;
+ const char *options;
+{
+ char *oli; /* option letter list index */
+ int optchar;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+
+ optarg = NULL;
+
+ /*
+ * XXX Some programs (like rsyncd) expect to be able to
+ * XXX re-initialize optind to 0 and have getopt_long(3)
+ * XXX properly function again. Work around this braindamage.
+ */
+ if (optind == 0)
+ optind = 1;
+
+ if (optreset)
+ nonopt_start = nonopt_end = -1;
+start:
+ if (optreset || !*place) { /* update scanning pointer */
+ optreset = 0;
+ if (optind >= nargc) { /* end of argument vector */
+ place = EMSG;
+ if (nonopt_end != -1) {
+ /* do permutation, if we have to */
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ else if (nonopt_start != -1) {
+ /*
+ * If we skipped non-options, set optind
+ * to the first of them.
+ */
+ optind = nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return -1;
+ }
+ if ((*(place = nargv[optind]) != '-')
+ || (place[1] == '\0')) { /* found non-option */
+ place = EMSG;
+ if (IN_ORDER) {
+ /*
+ * GNU extension:
+ * return non-option as argument to option 1
+ */
+ optarg = nargv[optind++];
+ return INORDER;
+ }
+ if (!PERMUTE) {
+ /*
+ * if no permutation wanted, stop parsing
+ * at first non-option
+ */
+ return -1;
+ }
+ /* do permutation */
+ if (nonopt_start == -1)
+ nonopt_start = optind;
+ else if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, nargv);
+ nonopt_start = optind -
+ (nonopt_end - nonopt_start);
+ nonopt_end = -1;
+ }
+ optind++;
+ /* process next argument */
+ goto start;
+ }
+ if (nonopt_start != -1 && nonopt_end == -1)
+ nonopt_end = optind;
+ if (place[1] && *++place == '-') { /* found "--" */
+ place++;
+ return -2;
+ }
+ }
+ if ((optchar = (int)*place++) == (int)':' ||
+ (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
+ /* option letter unknown or ':' */
+ if (!*place)
+ ++optind;
+ if (PRINT_ERROR)
+ warnx(illoptchar, optchar);
+ optopt = optchar;
+ return BADCH;
+ }
+ if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
+ /* XXX: what if no long options provided (called by getopt)? */
+ if (*place)
+ return -2;
+
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return BADARG;
+ } else /* white space */
+ place = nargv[optind];
+ /*
+ * Handle -W arg the same as --arg (which causes getopt to
+ * stop parsing).
+ */
+ return -2;
+ }
+ if (*++oli != ':') { /* doesn't take argument */
+ if (!*place)
+ ++optind;
+ } else { /* takes (optional) argument */
+ optarg = NULL;
+ if (*place) /* no white space */
+ optarg = (char *)place;
+ /* XXX: disable test for :: if PC? (GNU doesn't) */
+ else if (oli[1] != ':') { /* arg not optional */
+ if (++optind >= nargc) { /* no arg */
+ place = EMSG;
+ if (PRINT_ERROR)
+ warnx(recargchar, optchar);
+ optopt = optchar;
+ return BADARG;
+ } else
+ optarg = nargv[optind];
+ }
+ place = EMSG;
+ ++optind;
+ }
+ /* dump back option letter */
+ return optchar;
+}
+
+#ifdef REPLACE_GETOPT
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ *
+ * [eventually this will replace the real getopt]
+ */
+int
+getopt(nargc, nargv, options)
+ int nargc;
+ char * const *nargv;
+ const char *options;
+{
+ int retval;
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+
+ retval = getopt_internal(nargc, (char **)nargv, options);
+ if (retval == -2) {
+ ++optind;
+ /*
+ * We found an option (--), so if we skipped non-options,
+ * we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end, optind,
+ (char **)nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ retval = -1;
+ }
+ return retval;
+}
+#endif
+
+/*
+ * getopt_long --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt_long(nargc, nargv, options, long_options, idx)
+ int nargc;
+ char * const *nargv;
+ const char *options;
+ const struct option *long_options;
+ int *idx;
+{
+ int retval;
+
+#define IDENTICAL_INTERPRETATION(_x, _y) \
+ (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \
+ long_options[(_x)].flag == long_options[(_y)].flag && \
+ long_options[(_x)].val == long_options[(_y)].val)
+
+ _DIAGASSERT(nargv != NULL);
+ _DIAGASSERT(options != NULL);
+ _DIAGASSERT(long_options != NULL);
+ /* idx may be NULL */
+
+ retval = getopt_internal(nargc, (char **)nargv, options);
+ if (retval == -2) {
+ char *current_argv, *has_equal;
+ size_t current_argv_len;
+ int i, ambiguous, match;
+
+ current_argv = (char *)place;
+ match = -1;
+ ambiguous = 0;
+
+ optind++;
+ place = EMSG;
+
+ if (*current_argv == '\0') { /* found "--" */
+ /*
+ * We found an option (--), so if we skipped
+ * non-options, we have to permute.
+ */
+ if (nonopt_end != -1) {
+ permute_args(nonopt_start, nonopt_end,
+ optind, (char **)nargv);
+ optind -= nonopt_end - nonopt_start;
+ }
+ nonopt_start = nonopt_end = -1;
+ return -1;
+ }
+ if ((has_equal = strchr(current_argv, '=')) != NULL) {
+ /* argument found (--option=arg) */
+ current_argv_len = has_equal - current_argv;
+ has_equal++;
+ } else
+ current_argv_len = strlen(current_argv);
+
+ for (i = 0; long_options[i].name; i++) {
+ /* find matching long option */
+ if (strncmp(current_argv, long_options[i].name,
+ current_argv_len))
+ continue;
+
+ if (strlen(long_options[i].name) ==
+ (unsigned)current_argv_len) {
+ /* exact match */
+ match = i;
+ ambiguous = 0;
+ break;
+ }
+ if (match == -1) /* partial match */
+ match = i;
+ else if (!IDENTICAL_INTERPRETATION(i, match))
+ ambiguous = 1;
+ }
+ if (ambiguous) {
+ /* ambiguous abbreviation */
+ if (PRINT_ERROR)
+ warnx(ambig, (int)current_argv_len,
+ current_argv);
+ optopt = 0;
+ return BADCH;
+ }
+ if (match != -1) { /* option found */
+ if (long_options[match].has_arg == no_argument
+ && has_equal) {
+ if (PRINT_ERROR)
+ warnx(noarg, (int)current_argv_len,
+ current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless of
+ * flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ return BADARG;
+ }
+ if (long_options[match].has_arg == required_argument ||
+ long_options[match].has_arg == optional_argument) {
+ if (has_equal)
+ optarg = has_equal;
+ else if (long_options[match].has_arg ==
+ required_argument) {
+ /*
+ * optional argument doesn't use
+ * next nargv
+ */
+ optarg = nargv[optind++];
+ }
+ }
+ if ((long_options[match].has_arg == required_argument)
+ && (optarg == NULL)) {
+ /*
+ * Missing argument; leading ':'
+ * indicates no error should be generated
+ */
+ if (PRINT_ERROR)
+ warnx(recargstring, current_argv);
+ /*
+ * XXX: GNU sets optopt to val regardless
+ * of flag
+ */
+ if (long_options[match].flag == NULL)
+ optopt = long_options[match].val;
+ else
+ optopt = 0;
+ --optind;
+ return BADARG;
+ }
+ } else { /* unknown option */
+ if (PRINT_ERROR)
+ warnx(illoptstring, current_argv);
+ optopt = 0;
+ return BADCH;
+ }
+ if (long_options[match].flag) {
+ *long_options[match].flag = long_options[match].val;
+ retval = 0;
+ } else
+ retval = long_options[match].val;
+ if (idx)
+ *idx = match;
+ }
+ return retval;
+#undef IDENTICAL_INTERPRETATION
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/gmtime_r.c b/node_modules/mmmagic/deps/libmagic/src/gmtime_r.c
new file mode 100644
index 0000000..469ec65
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/gmtime_r.c
@@ -0,0 +1,19 @@
+/* $File: gmtime_r.c,v 1.2 2015/07/11 14:41:37 christos Exp $ */
+
+#include "file.h"
+#ifndef lint
+FILE_RCSID("@(#)$File: gmtime_r.c,v 1.2 2015/07/11 14:41:37 christos Exp $")
+#endif /* lint */
+#include <time.h>
+#include <string.h>
+
+/* asctime_r is not thread-safe anyway */
+struct tm *
+gmtime_r(const time_t *t, struct tm *tm)
+{
+ struct tm *tmp = gmtime(t);
+ if (tmp == NULL)
+ return NULL;
+ memcpy(tm, tmp, sizeof(*tm));
+ return tmp;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/is_tar.c b/node_modules/mmmagic/deps/libmagic/src/is_tar.c
new file mode 100644
index 0000000..1953a7f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/is_tar.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * is_tar() -- figure out whether file is a tar archive.
+ *
+ * Stolen (by the author!) from the public domain tar program:
+ * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
+ *
+ * @(#)list.c 1.18 9/23/86 Public Domain - gnu
+ *
+ * Comments changed and some code/comments reformatted
+ * for file command by Ian Darwin.
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: is_tar.c,v 1.39 2017/03/17 20:45:01 christos Exp $")
+#endif
+
+#include "magic.h"
+#include <string.h>
+#include <ctype.h>
+#include "tar.h"
+
+#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
+
+private int is_tar(const unsigned char *, size_t);
+private int from_oct(const char *, size_t); /* Decode octal number */
+
+static const char tartype[][32] = {
+ "tar archive",
+ "POSIX tar archive",
+ "POSIX tar archive (GNU)",
+};
+
+protected int
+file_is_tar(struct magic_set *ms, const unsigned char *buf, size_t nbytes)
+{
+ /*
+ * Do the tar test first, because if the first file in the tar
+ * archive starts with a dot, we can confuse it with an nroff file.
+ */
+ int tar;
+ int mime = ms->flags & MAGIC_MIME;
+
+ if ((ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION)) != 0)
+ return 0;
+
+ tar = is_tar(buf, nbytes);
+ if (tar < 1 || tar > 3)
+ return 0;
+
+ if (file_printf(ms, "%s", mime ? "application/x-tar" :
+ tartype[tar - 1]) == -1)
+ return -1;
+ return 1;
+}
+
+/*
+ * Return
+ * 0 if the checksum is bad (i.e., probably not a tar archive),
+ * 1 for old UNIX tar file,
+ * 2 for Unix Std (POSIX) tar file,
+ * 3 for GNU tar file.
+ */
+private int
+is_tar(const unsigned char *buf, size_t nbytes)
+{
+ const union record *header = (const union record *)(const void *)buf;
+ size_t i;
+ int sum, recsum;
+ const unsigned char *p, *ep;
+
+ if (nbytes < sizeof(*header))
+ return 0;
+
+ recsum = from_oct(header->header.chksum, sizeof(header->header.chksum));
+
+ sum = 0;
+ p = header->charptr;
+ ep = header->charptr + sizeof(*header);
+ while (p < ep)
+ sum += *p++;
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+ for (i = 0; i < sizeof(header->header.chksum); i++)
+ sum -= header->header.chksum[i];
+ sum += ' ' * sizeof(header->header.chksum);
+
+ if (sum != recsum)
+ return 0; /* Not a tar archive */
+
+ if (strncmp(header->header.magic, GNUTMAGIC,
+ sizeof(header->header.magic)) == 0)
+ return 3; /* GNU Unix Standard tar archive */
+
+ if (strncmp(header->header.magic, TMAGIC,
+ sizeof(header->header.magic)) == 0)
+ return 2; /* Unix Standard tar archive */
+
+ return 1; /* Old fashioned tar archive */
+}
+
+
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or non-octal).
+ */
+private int
+from_oct(const char *where, size_t digs)
+{
+ int value;
+
+ if (digs == 0)
+ return -1;
+
+ while (isspace((unsigned char)*where)) { /* Skip spaces */
+ where++;
+ if (digs-- == 0)
+ return -1; /* All blank field */
+ }
+ value = 0;
+ while (digs > 0 && isodigit(*where)) { /* Scan til non-octal */
+ value = (value << 3) | (*where++ - '0');
+ digs--;
+ }
+
+ if (digs > 0 && *where && !isspace((unsigned char)*where))
+ return -1; /* Ended on non-(space/NUL) */
+
+ return value;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/localtime_r.c b/node_modules/mmmagic/deps/libmagic/src/localtime_r.c
new file mode 100644
index 0000000..b0d996d
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/localtime_r.c
@@ -0,0 +1,19 @@
+/* $File: localtime_r.c,v 1.2 2015/07/11 14:41:37 christos Exp $ */
+
+#include "file.h"
+#ifndef lint
+FILE_RCSID("@(#)$File: localtime_r.c,v 1.2 2015/07/11 14:41:37 christos Exp $")
+#endif /* lint */
+#include <time.h>
+#include <string.h>
+
+/* asctime_r is not thread-safe anyway */
+struct tm *
+localtime_r(const time_t *t, struct tm *tm)
+{
+ struct tm *tmp = localtime(t);
+ if (tmp == NULL)
+ return NULL;
+ memcpy(tm, tmp, sizeof(*tm));
+ return tmp;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/magic.c b/node_modules/mmmagic/deps/libmagic/src/magic.c
new file mode 100644
index 0000000..91c9d82
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/magic.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) Christos Zoulas 2003.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+// XXX: change by mscdex
+#ifdef _MSC_VER
+#include <windows.h>
+#include <shlwapi.h>
+#endif
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: magic.c,v 1.102 2017/08/28 13:39:18 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+
+#include <stdlib.h>
+// XXX: change by mscdex
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#ifdef QUICK
+#include <sys/mman.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h> /* for PIPE_BUF */
+#endif
+
+#if defined(HAVE_UTIMES)
+# include <sys/time.h>
+#elif defined(HAVE_UTIME)
+# if defined(HAVE_SYS_UTIME_H)
+# include <sys/utime.h>
+# elif defined(HAVE_UTIME_H)
+# include <utime.h>
+# endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for read() */
+#endif
+
+#ifndef PIPE_BUF
+/* Get the PIPE_BUF from pathconf */
+#ifdef _PC_PIPE_BUF
+#define PIPE_BUF pathconf(".", _PC_PIPE_BUF)
+#else
+#define PIPE_BUF 512
+#endif
+#endif
+
+private void close_and_restore(const struct magic_set *, const char *, int,
+ const struct stat *);
+private int unreadable_info(struct magic_set *, mode_t, const char *);
+private const char* get_default_magic(void);
+#ifndef COMPILE_ONLY
+private const char *file_or_fd(struct magic_set *, const char *, int);
+#endif
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+
+#ifdef WIN32
+/* HINSTANCE of this shared library. Needed for get_default_magic() */
+static HINSTANCE _w32_dll_instance = NULL;
+
+static void
+_w32_append_path(char **hmagicpath, const char *fmt, ...)
+{
+ char *tmppath;
+ char *newpath;
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (vasprintf(&tmppath, fmt, ap) < 0) {
+ va_end(ap);
+ return;
+ }
+ va_end(ap);
+
+ if (access(tmppath, R_OK) == -1)
+ goto out;
+
+ if (*hmagicpath == NULL) {
+ *hmagicpath = tmppath;
+ return;
+ }
+
+ if (asprintf(&newpath, "%s%c%s", *hmagicpath, PATHSEP, tmppath) < 0)
+ goto out;
+
+ free(*hmagicpath);
+ free(tmppath);
+ *hmagicpath = newpath;
+ return;
+out:
+ free(tmppath);
+}
+
+static void
+_w32_get_magic_relative_to(char **hmagicpath, HINSTANCE module)
+{
+ static const char *trypaths[] = {
+ "%s/share/misc/magic.mgc",
+ "%s/magic.mgc",
+ };
+ LPSTR dllpath;
+ size_t sp;
+
+ dllpath = calloc(MAX_PATH + 1, sizeof(*dllpath));
+
+ if (!GetModuleFileNameA(module, dllpath, MAX_PATH))
+ goto out;
+
+ PathRemoveFileSpecA(dllpath);
+
+ if (module) {
+ char exepath[MAX_PATH];
+ GetModuleFileNameA(NULL, exepath, MAX_PATH);
+ PathRemoveFileSpecA(exepath);
+ if (stricmp(exepath, dllpath) == 0)
+ goto out;
+ }
+
+ sp = strlen(dllpath);
+ if (sp > 3 && stricmp(&dllpath[sp - 3], "bin") == 0) {
+ _w32_append_path(hmagicpath,
+ "%s/../share/misc/magic.mgc", dllpath);
+ goto out;
+ }
+
+ for (sp = 0; sp < __arraycount(trypaths); sp++)
+ _w32_append_path(hmagicpath, trypaths[sp], dllpath);
+out:
+ free(dllpath);
+}
+
+/* Placate GCC by offering a sacrificial previous prototype */
+BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID);
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
+ LPVOID lpvReserved __attribute__((__unused__)))
+{
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ _w32_dll_instance = hinstDLL;
+ return 1;
+}
+#endif
+
+private const char *
+get_default_magic(void)
+{
+ static const char hmagic[] = "/.magic/magic.mgc";
+ static char *default_magic;
+ char *home, *hmagicpath;
+
+#ifndef WIN32
+ struct stat st;
+
+ if (default_magic) {
+ free(default_magic);
+ default_magic = NULL;
+ }
+ if ((home = getenv("HOME")) == NULL)
+ return MAGIC;
+
+ if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0)
+ return MAGIC;
+ if (stat(hmagicpath, &st) == -1) {
+ free(hmagicpath);
+ if (asprintf(&hmagicpath, "%s/.magic", home) < 0)
+ return MAGIC;
+ if (stat(hmagicpath, &st) == -1)
+ goto out;
+ if (S_ISDIR(st.st_mode)) {
+ free(hmagicpath);
+ if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0)
+ return MAGIC;
+ if (access(hmagicpath, R_OK) == -1)
+ goto out;
+ }
+ }
+
+ if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0)
+ goto out;
+ free(hmagicpath);
+ return default_magic;
+out:
+ default_magic = NULL;
+ free(hmagicpath);
+ return MAGIC;
+#else
+ hmagicpath = NULL;
+
+ if (default_magic) {
+ free(default_magic);
+ default_magic = NULL;
+ }
+
+ /* First, try to get a magic file from user-application data */
+ if ((home = getenv("LOCALAPPDATA")) != NULL)
+ _w32_append_path(&hmagicpath, "%s%s", home, hmagic);
+
+ /* Second, try to get a magic file from the user profile data */
+ if ((home = getenv("USERPROFILE")) != NULL)
+ _w32_append_path(&hmagicpath,
+ "%s/Local Settings/Application Data%s", home, hmagic);
+
+ /* Third, try to get a magic file from Common Files */
+ if ((home = getenv("COMMONPROGRAMFILES")) != NULL)
+ _w32_append_path(&hmagicpath, "%s%s", home, hmagic);
+
+ /* Fourth, try to get magic file relative to exe location */
+ _w32_get_magic_relative_to(&hmagicpath, NULL);
+
+ /* Fifth, try to get magic file relative to dll location */
+ _w32_get_magic_relative_to(&hmagicpath, _w32_dll_instance);
+
+ /* Avoid MAGIC constant - it likely points to a file within MSys tree */
+ default_magic = hmagicpath;
+ return default_magic;
+#endif
+}
+
+public const char *
+magic_getpath(const char *magicfile, int action)
+{
+ if (magicfile != NULL)
+ return magicfile;
+
+ magicfile = getenv("MAGIC");
+ if (magicfile != NULL)
+ return magicfile;
+
+ return action == FILE_LOAD ? get_default_magic() : MAGIC;
+}
+
+public struct magic_set *
+magic_open(int flags)
+{
+ return file_ms_alloc(flags);
+}
+
+private int
+unreadable_info(struct magic_set *ms, mode_t md, const char *file)
+{
+ if (file) {
+ /* We cannot open it, but we were able to stat it. */
+ if (access(file, W_OK) == 0)
+ if (file_printf(ms, "writable, ") == -1)
+ return -1;
+ if (access(file, X_OK) == 0)
+ if (file_printf(ms, "executable, ") == -1)
+ return -1;
+ }
+ if (S_ISREG(md))
+ if (file_printf(ms, "regular file, ") == -1)
+ return -1;
+ if (file_printf(ms, "no read permission") == -1)
+ return -1;
+ return 0;
+}
+
+public void
+magic_close(struct magic_set *ms)
+{
+ if (ms == NULL)
+ return;
+ file_ms_free(ms);
+}
+
+/*
+ * load a magic file
+ */
+public int
+magic_load(struct magic_set *ms, const char *magicfile)
+{
+ if (ms == NULL)
+ return -1;
+ return file_apprentice(ms, magicfile, FILE_LOAD);
+}
+
+#ifndef COMPILE_ONLY
+/*
+ * Install a set of compiled magic buffers.
+ */
+public int
+magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes,
+ size_t nbufs)
+{
+ if (ms == NULL)
+ return -1;
+ return buffer_apprentice(ms, (struct magic **)bufs, sizes, nbufs);
+}
+#endif
+
+public int
+magic_compile(struct magic_set *ms, const char *magicfile)
+{
+ if (ms == NULL)
+ return -1;
+ return file_apprentice(ms, magicfile, FILE_COMPILE);
+}
+
+public int
+magic_check(struct magic_set *ms, const char *magicfile)
+{
+ if (ms == NULL)
+ return -1;
+ return file_apprentice(ms, magicfile, FILE_CHECK);
+}
+
+public int
+magic_list(struct magic_set *ms, const char *magicfile)
+{
+ if (ms == NULL)
+ return -1;
+ return file_apprentice(ms, magicfile, FILE_LIST);
+}
+
+private void
+close_and_restore(const struct magic_set *ms, const char *name, int fd,
+ const struct stat *sb)
+{
+ if (fd == STDIN_FILENO || name == NULL)
+ return;
+ (void) close(fd);
+
+ if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) {
+ /*
+ * Try to restore access, modification times if read it.
+ * This is really *bad* because it will modify the status
+ * time of the file... And of course this will affect
+ * backup programs
+ */
+#ifdef HAVE_UTIMES
+ struct timeval utsbuf[2];
+ (void)memset(utsbuf, 0, sizeof(utsbuf));
+ utsbuf[0].tv_sec = sb->st_atime;
+ utsbuf[1].tv_sec = sb->st_mtime;
+
+ (void) utimes(name, utsbuf); /* don't care if loses */
+#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H)
+ struct utimbuf utbuf;
+
+ (void)memset(&utbuf, 0, sizeof(utbuf));
+ utbuf.actime = sb->st_atime;
+ utbuf.modtime = sb->st_mtime;
+ (void) utime(name, &utbuf); /* don't care if loses */
+#endif
+ }
+}
+
+#ifndef COMPILE_ONLY
+
+/*
+ * find type of descriptor
+ */
+public const char *
+magic_descriptor(struct magic_set *ms, int fd)
+{
+ if (ms == NULL)
+ return NULL;
+ return file_or_fd(ms, NULL, fd);
+}
+
+/*
+ * find type of named file
+ */
+public const char *
+magic_file(struct magic_set *ms, const char *inname)
+{
+ if (ms == NULL)
+ return NULL;
+ return file_or_fd(ms, inname, STDIN_FILENO);
+}
+
+private const char *
+file_or_fd(struct magic_set *ms, const char *inname, int fd)
+{
+ int rv = -1;
+ unsigned char *buf;
+ struct stat sb;
+ ssize_t nbytes = 0; /* number of bytes read from a datafile */
+ int ispipe = 0;
+ off_t pos = (off_t)-1;
+
+ if (file_reset(ms, 1) == -1)
+ goto out;
+
+ /*
+ * one extra for terminating '\0', and
+ * some overlapping space for matches near EOF
+ */
+#define SLOP (1 + sizeof(union VALUETYPE))
+ if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL)
+ return NULL;
+
+ switch (file_fsmagic(ms, inname, &sb)) {
+ case -1: /* error */
+ goto done;
+ case 0: /* nothing found */
+ break;
+ default: /* matched it and printed type */
+ rv = 0;
+ goto done;
+ }
+
+#ifdef WIN32
+ /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */
+ if (fd == STDIN_FILENO)
+ _setmode(STDIN_FILENO, O_BINARY);
+#endif
+
+ if (inname == NULL) {
+ if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
+ ispipe = 1;
+ else
+ pos = lseek(fd, (off_t)0, SEEK_CUR);
+ } else {
+ int flags = O_RDONLY|O_BINARY;
+ int okstat = stat(inname, &sb) == 0;
+
+ if (okstat && S_ISFIFO(sb.st_mode)) {
+#ifdef O_NONBLOCK
+ flags |= O_NONBLOCK;
+#endif
+ ispipe = 1;
+ }
+
+ errno = 0;
+ if ((fd = open(inname, flags)) < 0) {
+#ifdef WIN32
+ /*
+ * Can't stat, can't open. It may have been opened in
+ * fsmagic, so if the user doesn't have read permission,
+ * allow it to say so; otherwise an error was probably
+ * displayed in fsmagic.
+ */
+ if (!okstat && errno == EACCES) {
+ sb.st_mode = S_IFBLK;
+ okstat = 1;
+ }
+#endif
+ if (okstat &&
+ unreadable_info(ms, sb.st_mode, inname) == -1)
+ goto done;
+ rv = 0;
+ goto done;
+ }
+#ifdef O_NONBLOCK
+ if ((flags = fcntl(fd, F_GETFL)) != -1) {
+ flags &= ~O_NONBLOCK;
+ (void)fcntl(fd, F_SETFL, flags);
+ }
+#endif
+ }
+
+ /*
+ * try looking at the first ms->bytes_max bytes
+ */
+ if (ispipe) {
+ ssize_t r = 0;
+
+ while ((r = sread(fd, (void *)&buf[nbytes],
+ (size_t)(ms->bytes_max - nbytes), 1)) > 0) {
+ nbytes += r;
+ if (r < PIPE_BUF) break;
+ }
+
+ if (nbytes == 0 && inname) {
+ /* We can not read it, but we were able to stat it. */
+ if (unreadable_info(ms, sb.st_mode, inname) == -1)
+ goto done;
+ rv = 0;
+ goto done;
+ }
+
+ } else {
+ /* Windows refuses to read from a big console buffer. */
+ size_t howmany =
+#if defined(WIN32)
+ _isatty(fd) ? 8 * 1024 :
+#endif
+ ms->bytes_max;
+ if ((nbytes = read(fd, (char *)buf, howmany)) == -1) {
+ if (inname == NULL && fd != STDIN_FILENO)
+ file_error(ms, errno, "cannot read fd %d", fd);
+ else
+ file_error(ms, errno, "cannot read `%s'",
+ inname == NULL ? "/dev/stdin" : inname);
+ goto done;
+ }
+ }
+
+ (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
+ if (file_buffer(ms, fd, inname, buf, (size_t)nbytes) == -1)
+ goto done;
+ rv = 0;
+done:
+ free(buf);
+ if (fd != -1) {
+ if (pos != (off_t)-1)
+ (void)lseek(fd, pos, SEEK_SET);
+ close_and_restore(ms, inname, fd, &sb);
+ }
+out:
+ return rv == 0 ? file_getbuffer(ms) : NULL;
+}
+
+
+public const char *
+magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
+{
+ if (ms == NULL)
+ return NULL;
+ if (file_reset(ms, 1) == -1)
+ return NULL;
+ /*
+ * The main work is done here!
+ * We have the file name and/or the data buffer to be identified.
+ */
+ if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
+ return NULL;
+ }
+ return file_getbuffer(ms);
+}
+#endif
+
+public const char *
+magic_error(struct magic_set *ms)
+{
+ if (ms == NULL)
+ return "Magic database is not open";
+ return (ms->event_flags & EVENT_HAD_ERR) ? ms->o.buf : NULL;
+}
+
+public int
+magic_errno(struct magic_set *ms)
+{
+ if (ms == NULL)
+ return EINVAL;
+ return (ms->event_flags & EVENT_HAD_ERR) ? ms->error : 0;
+}
+
+public int
+magic_getflags(struct magic_set *ms)
+{
+ if (ms == NULL)
+ return -1;
+
+ return ms->flags;
+}
+
+public int
+magic_setflags(struct magic_set *ms, int flags)
+{
+ if (ms == NULL)
+ return -1;
+#if !defined(HAVE_UTIME) && !defined(HAVE_UTIMES)
+ if (flags & MAGIC_PRESERVE_ATIME)
+ return -1;
+#endif
+ ms->flags = flags;
+ return 0;
+}
+
+public int
+magic_version(void)
+{
+ return MAGIC_VERSION;
+}
+
+public int
+magic_setparam(struct magic_set *ms, int param, const void *val)
+{
+ switch (param) {
+ case MAGIC_PARAM_INDIR_MAX:
+ ms->indir_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_NAME_MAX:
+ ms->name_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_ELF_PHNUM_MAX:
+ ms->elf_phnum_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_ELF_SHNUM_MAX:
+ ms->elf_shnum_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_ELF_NOTES_MAX:
+ ms->elf_notes_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_REGEX_MAX:
+ ms->elf_notes_max = (uint16_t)*(const size_t *)val;
+ return 0;
+ case MAGIC_PARAM_BYTES_MAX:
+ ms->bytes_max = *(const size_t *)val;
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+public int
+magic_getparam(struct magic_set *ms, int param, void *val)
+{
+ switch (param) {
+ case MAGIC_PARAM_INDIR_MAX:
+ *(size_t *)val = ms->indir_max;
+ return 0;
+ case MAGIC_PARAM_NAME_MAX:
+ *(size_t *)val = ms->name_max;
+ return 0;
+ case MAGIC_PARAM_ELF_PHNUM_MAX:
+ *(size_t *)val = ms->elf_phnum_max;
+ return 0;
+ case MAGIC_PARAM_ELF_SHNUM_MAX:
+ *(size_t *)val = ms->elf_shnum_max;
+ return 0;
+ case MAGIC_PARAM_ELF_NOTES_MAX:
+ *(size_t *)val = ms->elf_notes_max;
+ return 0;
+ case MAGIC_PARAM_REGEX_MAX:
+ *(size_t *)val = ms->regex_max;
+ return 0;
+ case MAGIC_PARAM_BYTES_MAX:
+ *(size_t *)val = ms->bytes_max;
+ return 0;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/magic.h b/node_modules/mmmagic/deps/libmagic/src/magic.h
new file mode 100644
index 0000000..2d707d5
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/magic.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) Christos Zoulas 2003.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _MAGIC_H
+#define _MAGIC_H
+
+#include <sys/types.h>
+
+#define MAGIC_NONE 0x0000000 /* No flags */
+#define MAGIC_DEBUG 0x0000001 /* Turn on debugging */
+#define MAGIC_SYMLINK 0x0000002 /* Follow symlinks */
+#define MAGIC_COMPRESS 0x0000004 /* Check inside compressed files */
+#define MAGIC_DEVICES 0x0000008 /* Look at the contents of devices */
+#define MAGIC_MIME_TYPE 0x0000010 /* Return the MIME type */
+#define MAGIC_CONTINUE 0x0000020 /* Return all matches */
+#define MAGIC_CHECK 0x0000040 /* Print warnings to stderr */
+#define MAGIC_PRESERVE_ATIME 0x0000080 /* Restore access time on exit */
+#define MAGIC_RAW 0x0000100 /* Don't convert unprintable chars */
+#define MAGIC_ERROR 0x0000200 /* Handle ENOENT etc as real errors */
+#define MAGIC_MIME_ENCODING 0x0000400 /* Return the MIME encoding */
+#define MAGIC_MIME (MAGIC_MIME_TYPE|MAGIC_MIME_ENCODING)
+#define MAGIC_APPLE 0x0000800 /* Return the Apple creator/type */
+#define MAGIC_EXTENSION 0x1000000 /* Return a /-separated list of
+ * extensions */
+#define MAGIC_COMPRESS_TRANSP 0x2000000 /* Check inside compressed files
+ * but not report compression */
+#define MAGIC_NODESC (MAGIC_EXTENSION|MAGIC_MIME|MAGIC_APPLE)
+
+#define MAGIC_NO_CHECK_COMPRESS 0x0001000 /* Don't check for compressed files */
+#define MAGIC_NO_CHECK_TAR 0x0002000 /* Don't check for tar files */
+#define MAGIC_NO_CHECK_SOFT 0x0004000 /* Don't check magic entries */
+#define MAGIC_NO_CHECK_APPTYPE 0x0008000 /* Don't check application type */
+#define MAGIC_NO_CHECK_ELF 0x0010000 /* Don't check for elf details */
+#define MAGIC_NO_CHECK_TEXT 0x0020000 /* Don't check for text files */
+#define MAGIC_NO_CHECK_CDF 0x0040000 /* Don't check for cdf files */
+#define MAGIC_NO_CHECK_TOKENS 0x0100000 /* Don't check tokens */
+#define MAGIC_NO_CHECK_ENCODING 0x0200000 /* Don't check text encodings */
+
+/* No built-in tests; only consult the magic file */
+#define MAGIC_NO_CHECK_BUILTIN ( \
+ MAGIC_NO_CHECK_COMPRESS | \
+ MAGIC_NO_CHECK_TAR | \
+/* MAGIC_NO_CHECK_SOFT | */ \
+ MAGIC_NO_CHECK_APPTYPE | \
+ MAGIC_NO_CHECK_ELF | \
+ MAGIC_NO_CHECK_TEXT | \
+ MAGIC_NO_CHECK_CDF | \
+ MAGIC_NO_CHECK_TOKENS | \
+ MAGIC_NO_CHECK_ENCODING | \
+ 0 \
+)
+
+#define MAGIC_SNPRINTB "\177\020\
+b\0debug\0\
+b\1symlink\0\
+b\2compress\0\
+b\3devices\0\
+b\4mime_type\0\
+b\5continue\0\
+b\6check\0\
+b\7preserve_atime\0\
+b\10raw\0\
+b\11error\0\
+b\12mime_encoding\0\
+b\13apple\0\
+b\14no_check_compress\0\
+b\15no_check_tar\0\
+b\16no_check_soft\0\
+b\17no_check_sapptype\0\
+b\20no_check_elf\0\
+b\21no_check_text\0\
+b\22no_check_cdf\0\
+b\23no_check_reserved0\0\
+b\24no_check_tokens\0\
+b\25no_check_encoding\0\
+b\26no_check_reserved1\0\
+b\27no_check_reserved2\0\
+b\30extension\0\
+b\31transp_compression\0\
+"
+
+/* Defined for backwards compatibility (renamed) */
+#define MAGIC_NO_CHECK_ASCII MAGIC_NO_CHECK_TEXT
+
+/* Defined for backwards compatibility; do nothing */
+#define MAGIC_NO_CHECK_FORTRAN 0x000000 /* Don't check ascii/fortran */
+#define MAGIC_NO_CHECK_TROFF 0x000000 /* Don't check ascii/troff */
+
+#define MAGIC_VERSION 532 /* This implementation */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct magic_set *magic_t;
+magic_t magic_open(int);
+void magic_close(magic_t);
+
+const char *magic_getpath(const char *, int);
+const char *magic_file(magic_t, const char *);
+const char *magic_descriptor(magic_t, int);
+const char *magic_buffer(magic_t, const void *, size_t);
+
+const char *magic_error(magic_t);
+int magic_getflags(magic_t);
+int magic_setflags(magic_t, int);
+
+int magic_version(void);
+int magic_load(magic_t, const char *);
+int magic_load_buffers(magic_t, void **, size_t *, size_t);
+
+int magic_compile(magic_t, const char *);
+int magic_check(magic_t, const char *);
+int magic_list(magic_t, const char *);
+int magic_errno(magic_t);
+
+#define MAGIC_PARAM_INDIR_MAX 0
+#define MAGIC_PARAM_NAME_MAX 1
+#define MAGIC_PARAM_ELF_PHNUM_MAX 2
+#define MAGIC_PARAM_ELF_SHNUM_MAX 3
+#define MAGIC_PARAM_ELF_NOTES_MAX 4
+#define MAGIC_PARAM_REGEX_MAX 5
+#define MAGIC_PARAM_BYTES_MAX 6
+
+int magic_setparam(magic_t, int, const void *);
+int magic_getparam(magic_t, int, void *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _MAGIC_H */
diff --git a/node_modules/mmmagic/deps/libmagic/src/mygetopt.h b/node_modules/mmmagic/deps/libmagic/src/mygetopt.h
new file mode 100644
index 0000000..ef87525
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/mygetopt.h
@@ -0,0 +1,68 @@
+/* $NetBSD: getopt.h,v 1.8 2007/11/06 19:21:18 christos Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GETOPT_H_
+#define _GETOPT_H_
+
+#include <unistd.h>
+
+/*
+ * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
+ */
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+struct option {
+ /* name of long option */
+ const char *name;
+ /*
+ * one of no_argument, required_argument, and optional_argument:
+ * whether option takes an argument
+ */
+ int has_arg;
+ /* if not NULL, set *flag to val when option found */
+ int *flag;
+ /* if flag not NULL, value to set *flag to; else return value */
+ int val;
+};
+
+int getopt_long(int, char * const *, const char *,
+ const struct option *, int *);
+
+#endif /* !_GETOPT_H_ */
diff --git a/node_modules/mmmagic/deps/libmagic/src/pread.c b/node_modules/mmmagic/deps/libmagic/src/pread.c
new file mode 100644
index 0000000..0de518f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/pread.c
@@ -0,0 +1,26 @@
+#include "file.h"
+#ifndef lint
+FILE_RCSID("@(#)$File: pread.c,v 1.3 2014/09/15 19:11:25 christos Exp $")
+#endif /* lint */
+#include <fcntl.h>
+// XXX: change by mscdex
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+ssize_t
+pread(int fd, void *buf, size_t len, off_t off) {
+ off_t old;
+ ssize_t rv;
+
+ if ((old = lseek(fd, off, SEEK_SET)) == -1)
+ return -1;
+
+ if ((rv = read(fd, buf, len)) == -1)
+ return -1;
+
+ if (lseek(fd, old, SEEK_SET) == -1)
+ return -1;
+
+ return rv;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/print.c b/node_modules/mmmagic/deps/libmagic/src/print.c
new file mode 100644
index 0000000..0b91863
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/print.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * print.c - debugging printout routines
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: print.c,v 1.82 2017/02/10 18:14:01 christos Exp $")
+#endif /* lint */
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+
+#define SZOF(a) (sizeof(a) / sizeof(a[0]))
+
+#include "cdf.h"
+
+#ifndef COMPILE_ONLY
+protected void
+file_mdump(struct magic *m)
+{
+ static const char optyp[] = { FILE_OPS };
+ char tbuf[26];
+
+ (void) fprintf(stderr, "%u: %.*s %u", m->lineno,
+ (m->cont_level & 7) + 1, ">>>>>>>>", m->offset);
+
+ if (m->flag & INDIR) {
+ (void) fprintf(stderr, "(%s,",
+ /* Note: type is unsigned */
+ (m->in_type < file_nnames) ? file_names[m->in_type] :
+ "*bad in_type*");
+ if (m->in_op & FILE_OPINVERSE)
+ (void) fputc('~', stderr);
+ (void) fprintf(stderr, "%c%u),",
+ ((size_t)(m->in_op & FILE_OPS_MASK) <
+ SZOF(optyp)) ? optyp[m->in_op & FILE_OPS_MASK] : '?',
+ m->in_offset);
+ }
+ (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "",
+ /* Note: type is unsigned */
+ (m->type < file_nnames) ? file_names[m->type] : "*bad type");
+ if (m->mask_op & FILE_OPINVERSE)
+ (void) fputc('~', stderr);
+
+ if (IS_STRING(m->type)) {
+ if (m->str_flags) {
+ (void) fputc('/', stderr);
+ if (m->str_flags & STRING_COMPACT_WHITESPACE)
+ (void) fputc(CHAR_COMPACT_WHITESPACE, stderr);
+ if (m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE)
+ (void) fputc(CHAR_COMPACT_OPTIONAL_WHITESPACE,
+ stderr);
+ if (m->str_flags & STRING_IGNORE_LOWERCASE)
+ (void) fputc(CHAR_IGNORE_LOWERCASE, stderr);
+ if (m->str_flags & STRING_IGNORE_UPPERCASE)
+ (void) fputc(CHAR_IGNORE_UPPERCASE, stderr);
+ if (m->str_flags & REGEX_OFFSET_START)
+ (void) fputc(CHAR_REGEX_OFFSET_START, stderr);
+ if (m->str_flags & STRING_TEXTTEST)
+ (void) fputc(CHAR_TEXTTEST, stderr);
+ if (m->str_flags & STRING_BINTEST)
+ (void) fputc(CHAR_BINTEST, stderr);
+ if (m->str_flags & PSTRING_1_BE)
+ (void) fputc(CHAR_PSTRING_1_BE, stderr);
+ if (m->str_flags & PSTRING_2_BE)
+ (void) fputc(CHAR_PSTRING_2_BE, stderr);
+ if (m->str_flags & PSTRING_2_LE)
+ (void) fputc(CHAR_PSTRING_2_LE, stderr);
+ if (m->str_flags & PSTRING_4_BE)
+ (void) fputc(CHAR_PSTRING_4_BE, stderr);
+ if (m->str_flags & PSTRING_4_LE)
+ (void) fputc(CHAR_PSTRING_4_LE, stderr);
+ if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF)
+ (void) fputc(
+ CHAR_PSTRING_LENGTH_INCLUDES_ITSELF,
+ stderr);
+ }
+ if (m->str_range)
+ (void) fprintf(stderr, "/%u", m->str_range);
+ }
+ else {
+ if ((size_t)(m->mask_op & FILE_OPS_MASK) < SZOF(optyp))
+ (void) fputc(optyp[m->mask_op & FILE_OPS_MASK], stderr);
+ else
+ (void) fputc('?', stderr);
+
+ if (m->num_mask) {
+ (void) fprintf(stderr, "%.8llx",
+ (unsigned long long)m->num_mask);
+ }
+ }
+ (void) fprintf(stderr, ",%c", m->reln);
+
+ if (m->reln != 'x') {
+ switch (m->type) {
+ case FILE_BYTE:
+ case FILE_SHORT:
+ case FILE_LONG:
+ case FILE_LESHORT:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_BESHORT:
+ case FILE_BELONG:
+ case FILE_INDIRECT:
+ (void) fprintf(stderr, "%d", m->value.l);
+ break;
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ case FILE_QUAD:
+ (void) fprintf(stderr, "%" INT64_T_FORMAT "d",
+ (unsigned long long)m->value.q);
+ break;
+ case FILE_PSTRING:
+ case FILE_STRING:
+ case FILE_REGEX:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ case FILE_SEARCH:
+ file_showstr(stderr, m->value.s, (size_t)m->vallen);
+ break;
+ case FILE_DATE:
+ case FILE_LEDATE:
+ case FILE_BEDATE:
+ case FILE_MEDATE:
+ (void)fprintf(stderr, "%s,",
+ file_fmttime(m->value.l, 0, tbuf));
+ break;
+ case FILE_LDATE:
+ case FILE_LELDATE:
+ case FILE_BELDATE:
+ case FILE_MELDATE:
+ (void)fprintf(stderr, "%s,",
+ file_fmttime(m->value.l, FILE_T_LOCAL, tbuf));
+ break;
+ case FILE_QDATE:
+ case FILE_LEQDATE:
+ case FILE_BEQDATE:
+ (void)fprintf(stderr, "%s,",
+ file_fmttime(m->value.q, 0, tbuf));
+ break;
+ case FILE_QLDATE:
+ case FILE_LEQLDATE:
+ case FILE_BEQLDATE:
+ (void)fprintf(stderr, "%s,",
+ file_fmttime(m->value.q, FILE_T_LOCAL, tbuf));
+ break;
+ case FILE_QWDATE:
+ case FILE_LEQWDATE:
+ case FILE_BEQWDATE:
+ (void)fprintf(stderr, "%s,",
+ file_fmttime(m->value.q, FILE_T_WINDOWS, tbuf));
+ break;
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ (void) fprintf(stderr, "%G", m->value.f);
+ break;
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ (void) fprintf(stderr, "%G", m->value.d);
+ break;
+ case FILE_DEFAULT:
+ /* XXX - do anything here? */
+ break;
+ case FILE_USE:
+ case FILE_NAME:
+ case FILE_DER:
+ (void) fprintf(stderr, "'%s'", m->value.s);
+ break;
+ default:
+ (void) fprintf(stderr, "*bad type %d*", m->type);
+ break;
+ }
+ }
+ (void) fprintf(stderr, ",\"%s\"]\n", m->desc);
+}
+#endif
+
+/*VARARGS*/
+protected void
+file_magwarn(struct magic_set *ms, const char *f, ...)
+{
+ va_list va;
+
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
+
+ if (ms->file)
+ (void) fprintf(stderr, "%s, %lu: ", ms->file,
+ (unsigned long)ms->line);
+ (void) fprintf(stderr, "Warning: ");
+ va_start(va, f);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ (void) fputc('\n', stderr);
+}
+
+protected const char *
+file_fmttime(uint64_t v, int flags, char *buf)
+{
+ char *pp;
+ time_t t;
+ struct tm *tm, tmz;
+
+ if (flags & FILE_T_WINDOWS) {
+ struct timespec ts;
+ cdf_timestamp_to_timespec(&ts, CAST(cdf_timestamp_t, v));
+ t = ts.tv_sec;
+ } else {
+ // XXX: perhaps detect and print something if overflow
+ // on 32 bit time_t?
+ t = (time_t)v;
+ }
+
+ if (flags & FILE_T_LOCAL) {
+ tm = localtime_r(&t, &tmz);
+ } else {
+ tm = gmtime_r(&t, &tmz);
+ }
+ if (tm == NULL)
+ goto out;
+ pp = asctime_r(tm, buf);
+
+ if (pp == NULL)
+ goto out;
+ pp[strcspn(pp, "\n")] = '\0';
+ return pp;
+out:
+ return strcpy(buf, "*Invalid time*");
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/readcdf.c b/node_modules/mmmagic/deps/libmagic/src/readcdf.c
new file mode 100644
index 0000000..3d251d4
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/readcdf.c
@@ -0,0 +1,680 @@
+/*-
+ * Copyright (c) 2008, 2016 Christos Zoulas
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: readcdf.c,v 1.65 2017/04/08 20:58:03 christos Exp $")
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+// XXX: change by mscdex
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "cdf.h"
+#include "magic.h"
+
+#ifndef __arraycount
+#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#define NOTMIME(ms) (((ms)->flags & MAGIC_MIME) == 0)
+
+static const struct nv {
+ const char *pattern;
+ const char *mime;
+} app2mime[] = {
+ { "Word", "msword", },
+ { "Excel", "vnd.ms-excel", },
+ { "Powerpoint", "vnd.ms-powerpoint", },
+ { "Crystal Reports", "x-rpt", },
+ { "Advanced Installer", "vnd.ms-msi", },
+ { "InstallShield", "vnd.ms-msi", },
+ { "Microsoft Patch Compiler", "vnd.ms-msi", },
+ { "NAnt", "vnd.ms-msi", },
+ { "Windows Installer", "vnd.ms-msi", },
+ { NULL, NULL, },
+}, name2mime[] = {
+ { "Book", "vnd.ms-excel", },
+ { "Workbook", "vnd.ms-excel", },
+ { "WordDocument", "msword", },
+ { "PowerPoint", "vnd.ms-powerpoint", },
+ { "DigitalSignature", "vnd.ms-msi", },
+ { NULL, NULL, },
+}, name2desc[] = {
+ { "Book", "Microsoft Excel", },
+ { "Workbook", "Microsoft Excel", },
+ { "WordDocument", "Microsoft Word", },
+ { "PowerPoint", "Microsoft PowerPoint", },
+ { "DigitalSignature", "Microsoft Installer", },
+ { NULL, NULL, },
+};
+
+static const struct cv {
+ uint64_t clsid[2];
+ const char *mime;
+} clsid2mime[] = {
+ {
+ { 0x00000000000c1084ULL, 0x46000000000000c0ULL },
+ "x-msi",
+ },
+ { { 0, 0 },
+ NULL,
+ },
+}, clsid2desc[] = {
+ {
+ { 0x00000000000c1084ULL, 0x46000000000000c0ULL },
+ "MSI Installer",
+ },
+ { { 0, 0 },
+ NULL,
+ },
+};
+
+private const char *
+cdf_clsid_to_mime(const uint64_t clsid[2], const struct cv *cv)
+{
+ size_t i;
+ for (i = 0; cv[i].mime != NULL; i++) {
+ if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1])
+ return cv[i].mime;
+ }
+#ifdef CDF_DEBUG
+ fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0],
+ clsid[1]);
+#endif
+ return NULL;
+}
+
+private const char *
+cdf_app_to_mime(const char *vbuf, const struct nv *nv)
+{
+ size_t i;
+ const char *rv = NULL;
+#ifdef USE_C_LOCALE
+ locale_t old_lc_ctype, c_lc_ctype;
+
+ c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0);
+ assert(c_lc_ctype != NULL);
+ old_lc_ctype = uselocale(c_lc_ctype);
+ assert(old_lc_ctype != NULL);
+#else
+ char *old_lc_ctype = setlocale(LC_CTYPE, "C");
+#endif
+ for (i = 0; nv[i].pattern != NULL; i++)
+ if (strcasestr(vbuf, nv[i].pattern) != NULL) {
+ rv = nv[i].mime;
+ break;
+ }
+#ifdef CDF_DEBUG
+ fprintf(stderr, "unknown app %s\n", vbuf);
+#endif
+#ifdef USE_C_LOCALE
+ (void)uselocale(old_lc_ctype);
+ freelocale(c_lc_ctype);
+#else
+ setlocale(LC_CTYPE, old_lc_ctype);
+#endif
+ return rv;
+}
+
+private int
+cdf_file_property_info(struct magic_set *ms, const cdf_property_info_t *info,
+ size_t count, const cdf_directory_t *root_storage)
+{
+ size_t i;
+ cdf_timestamp_t tp;
+ struct timespec ts;
+ char buf[64];
+ const char *str = NULL;
+ const char *s, *e;
+ int len;
+
+ if (!NOTMIME(ms) && root_storage)
+ str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
+ clsid2mime);
+
+ for (i = 0; i < count; i++) {
+ cdf_print_property_name(buf, sizeof(buf), info[i].pi_id);
+ switch (info[i].pi_type) {
+ case CDF_NULL:
+ break;
+ case CDF_SIGNED16:
+ if (NOTMIME(ms) && file_printf(ms, ", %s: %hd", buf,
+ info[i].pi_s16) == -1)
+ return -1;
+ break;
+ case CDF_SIGNED32:
+ if (NOTMIME(ms) && file_printf(ms, ", %s: %d", buf,
+ info[i].pi_s32) == -1)
+ return -1;
+ break;
+ case CDF_UNSIGNED32:
+ if (NOTMIME(ms) && file_printf(ms, ", %s: %u", buf,
+ info[i].pi_u32) == -1)
+ return -1;
+ break;
+ case CDF_FLOAT:
+ if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
+ info[i].pi_f) == -1)
+ return -1;
+ break;
+ case CDF_DOUBLE:
+ if (NOTMIME(ms) && file_printf(ms, ", %s: %g", buf,
+ info[i].pi_d) == -1)
+ return -1;
+ break;
+ case CDF_LENGTH32_STRING:
+ case CDF_LENGTH32_WSTRING:
+ len = info[i].pi_str.s_len;
+ if (len > 1) {
+ char vbuf[1024];
+ size_t j, k = 1;
+
+ if (info[i].pi_type == CDF_LENGTH32_WSTRING)
+ k++;
+ s = info[i].pi_str.s_buf;
+ e = info[i].pi_str.s_buf + len;
+ for (j = 0; s < e && j < sizeof(vbuf)
+ && len--; s += k) {
+ if (*s == '\0')
+ break;
+ if (isprint((unsigned char)*s))
+ vbuf[j++] = *s;
+ }
+ if (j == sizeof(vbuf))
+ --j;
+ vbuf[j] = '\0';
+ if (NOTMIME(ms)) {
+ if (vbuf[0]) {
+ if (file_printf(ms, ", %s: %s",
+ buf, vbuf) == -1)
+ return -1;
+ }
+ } else if (str == NULL && info[i].pi_id ==
+ CDF_PROPERTY_NAME_OF_APPLICATION) {
+ str = cdf_app_to_mime(vbuf, app2mime);
+ }
+ }
+ break;
+ case CDF_FILETIME:
+ tp = info[i].pi_tp;
+ if (tp != 0) {
+ char tbuf[64];
+ if (tp < 1000000000000000LL) {
+ cdf_print_elapsed_time(tbuf,
+ sizeof(tbuf), tp);
+ if (NOTMIME(ms) && file_printf(ms,
+ ", %s: %s", buf, tbuf) == -1)
+ return -1;
+ } else {
+ char *c, *ec;
+ cdf_timestamp_to_timespec(&ts, tp);
+ c = cdf_ctime(&ts.tv_sec, tbuf);
+ if (c != NULL &&
+ (ec = strchr(c, '\n')) != NULL)
+ *ec = '\0';
+
+ if (NOTMIME(ms) && file_printf(ms,
+ ", %s: %s", buf, c) == -1)
+ return -1;
+ }
+ }
+ break;
+ case CDF_CLIPBOARD:
+ break;
+ default:
+ return -1;
+ }
+ }
+ if (!NOTMIME(ms)) {
+ if (str == NULL)
+ return 0;
+ if (file_printf(ms, "application/%s", str) == -1)
+ return -1;
+ }
+ return 1;
+}
+
+private int
+cdf_file_catalog(struct magic_set *ms, const cdf_header_t *h,
+ const cdf_stream_t *sst)
+{
+ cdf_catalog_t *cat;
+ size_t i;
+ char buf[256];
+ cdf_catalog_entry_t *ce;
+
+ if (NOTMIME(ms)) {
+ if (file_printf(ms, "Microsoft Thumbs.db [") == -1)
+ return -1;
+ if (cdf_unpack_catalog(h, sst, &cat) == -1)
+ return -1;
+ ce = cat->cat_e;
+ /* skip first entry since it has a , or paren */
+ for (i = 1; i < cat->cat_num; i++)
+ if (file_printf(ms, "%s%s",
+ cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name),
+ i == cat->cat_num - 1 ? "]" : ", ") == -1) {
+ free(cat);
+ return -1;
+ }
+ free(cat);
+ } else {
+ if (file_printf(ms, "application/CDFV2") == -1)
+ return -1;
+ }
+ return 1;
+}
+
+private int
+cdf_file_summary_info(struct magic_set *ms, const cdf_header_t *h,
+ const cdf_stream_t *sst, const cdf_directory_t *root_storage)
+{
+ cdf_summary_info_header_t si;
+ cdf_property_info_t *info;
+ size_t count;
+ int m;
+
+ if (cdf_unpack_summary_info(sst, h, &si, &info, &count) == -1)
+ return -1;
+
+ if (NOTMIME(ms)) {
+ const char *str;
+
+ if (file_printf(ms, "Composite Document File V2 Document")
+ == -1)
+ return -1;
+
+ if (file_printf(ms, ", %s Endian",
+ si.si_byte_order == 0xfffe ? "Little" : "Big") == -1)
+ return -2;
+ switch (si.si_os) {
+ case 2:
+ if (file_printf(ms, ", Os: Windows, Version %d.%d",
+ si.si_os_version & 0xff,
+ (uint32_t)si.si_os_version >> 8) == -1)
+ return -2;
+ break;
+ case 1:
+ if (file_printf(ms, ", Os: MacOS, Version %d.%d",
+ (uint32_t)si.si_os_version >> 8,
+ si.si_os_version & 0xff) == -1)
+ return -2;
+ break;
+ default:
+ if (file_printf(ms, ", Os %d, Version: %d.%d", si.si_os,
+ si.si_os_version & 0xff,
+ (uint32_t)si.si_os_version >> 8) == -1)
+ return -2;
+ break;
+ }
+ if (root_storage) {
+ str = cdf_clsid_to_mime(root_storage->d_storage_uuid,
+ clsid2desc);
+ if (str) {
+ if (file_printf(ms, ", %s", str) == -1)
+ return -2;
+ }
+ }
+ }
+
+ m = cdf_file_property_info(ms, info, count, root_storage);
+ free(info);
+
+ return m == -1 ? -2 : m;
+}
+
+#ifdef notdef
+private char *
+format_clsid(char *buf, size_t len, const uint64_t uuid[2]) {
+ snprintf(buf, len, "%.8" PRIx64 "-%.4" PRIx64 "-%.4" PRIx64 "-%.4"
+ PRIx64 "-%.12" PRIx64,
+ (uuid[0] >> 32) & (uint64_t)0x000000000ffffffffULL,
+ (uuid[0] >> 16) & (uint64_t)0x0000000000000ffffULL,
+ (uuid[0] >> 0) & (uint64_t)0x0000000000000ffffULL,
+ (uuid[1] >> 48) & (uint64_t)0x0000000000000ffffULL,
+ (uuid[1] >> 0) & (uint64_t)0x0000fffffffffffffULL);
+ return buf;
+}
+#endif
+
+private int
+cdf_file_catalog_info(struct magic_set *ms, const cdf_info_t *info,
+ const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
+ const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn)
+{
+ int i;
+
+ if ((i = cdf_read_user_stream(info, h, sat, ssat, sst,
+ dir, "Catalog", scn)) == -1)
+ return i;
+#ifdef CDF_DEBUG
+ cdf_dump_catalog(h, scn);
+#endif
+ if ((i = cdf_file_catalog(ms, h, scn)) == -1)
+ return -1;
+ return i;
+}
+
+private int
+cdf_check_summary_info(struct magic_set *ms, const cdf_info_t *info,
+ const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat,
+ const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn,
+ const cdf_directory_t *root_storage, const char **expn)
+{
+ int i;
+ const char *str = NULL;
+ cdf_directory_t *d;
+ char name[__arraycount(d->d_name)];
+ size_t j, k;
+
+#ifdef CDF_DEBUG
+ cdf_dump_summary_info(h, scn);
+#endif
+ if ((i = cdf_file_summary_info(ms, h, scn, root_storage)) < 0) {
+ *expn = "Can't expand summary_info";
+ return i;
+ }
+ if (i == 1)
+ return i;
+ for (j = 0; str == NULL && j < dir->dir_len; j++) {
+ d = &dir->dir_tab[j];
+ for (k = 0; k < sizeof(name); k++)
+ name[k] = (char)cdf_tole2(d->d_name[k]);
+ str = cdf_app_to_mime(name,
+ NOTMIME(ms) ? name2desc : name2mime);
+ }
+ if (NOTMIME(ms)) {
+ if (str != NULL) {
+ if (file_printf(ms, "%s", str) == -1)
+ return -1;
+ i = 1;
+ }
+ } else {
+ if (str == NULL)
+ str = "vnd.ms-office";
+ if (file_printf(ms, "application/%s", str) == -1)
+ return -1;
+ i = 1;
+ }
+ if (i <= 0) {
+ i = cdf_file_catalog_info(ms, info, h, sat, ssat, sst,
+ dir, scn);
+ }
+ return i;
+}
+
+private struct sinfo {
+ const char *name;
+ const char *mime;
+ const char *sections[5];
+ const int types[5];
+} sectioninfo[] = {
+ { "Encrypted", "encrypted",
+ {
+ "EncryptedPackage", "EncryptedSummary",
+ NULL, NULL, NULL,
+ },
+ {
+ CDF_DIR_TYPE_USER_STREAM,
+ CDF_DIR_TYPE_USER_STREAM,
+ 0, 0, 0,
+
+ },
+ },
+ { "QuickBooks", "quickbooks",
+ {
+#if 0
+ "TaxForms", "PDFTaxForms", "modulesInBackup",
+#endif
+ "mfbu_header", NULL, NULL, NULL, NULL,
+ },
+ {
+#if 0
+ CDF_DIR_TYPE_USER_STORAGE,
+ CDF_DIR_TYPE_USER_STORAGE,
+ CDF_DIR_TYPE_USER_STREAM,
+#endif
+ CDF_DIR_TYPE_USER_STREAM,
+ 0, 0, 0, 0
+ },
+ },
+ { "Microsoft Excel", "vnd.ms-excel",
+ {
+ "Book", "Workbook", NULL, NULL, NULL,
+ },
+ {
+ CDF_DIR_TYPE_USER_STREAM,
+ CDF_DIR_TYPE_USER_STREAM,
+ 0, 0, 0,
+ },
+ },
+ { "Microsoft Word", "msword",
+ {
+ "WordDocument", NULL, NULL, NULL, NULL,
+ },
+ {
+ CDF_DIR_TYPE_USER_STREAM,
+ 0, 0, 0, 0,
+ },
+ },
+ { "Microsoft PowerPoint", "vnd.ms-powerpoint",
+ {
+ "PowerPoint", NULL, NULL, NULL, NULL,
+ },
+ {
+ CDF_DIR_TYPE_USER_STREAM,
+ 0, 0, 0, 0,
+ },
+ },
+ { "Microsoft Outlook Message", "vnd.ms-outlook",
+ {
+ "__properties_version1.0",
+ "__recip_version1.0_#00000000",
+ NULL, NULL, NULL,
+ },
+ {
+ CDF_DIR_TYPE_USER_STREAM,
+ CDF_DIR_TYPE_USER_STORAGE,
+ 0, 0, 0,
+ },
+ },
+};
+
+private int
+cdf_file_dir_info(struct magic_set *ms, const cdf_dir_t *dir)
+{
+ size_t sd, j;
+
+ for (sd = 0; sd < __arraycount(sectioninfo); sd++) {
+ const struct sinfo *si = &sectioninfo[sd];
+ for (j = 0; si->sections[j]; j++) {
+ if (cdf_find_stream(dir, si->sections[j], si->types[j])
+ > 0)
+ break;
+#ifdef CDF_DEBUG
+ fprintf(stderr, "Can't read %s\n", si->sections[j]);
+#endif
+ }
+ if (si->sections[j] == NULL)
+ continue;
+ if (NOTMIME(ms)) {
+ if (file_printf(ms, "CDFV2 %s", si->name) == -1)
+ return -1;
+ } else {
+ if (file_printf(ms, "application/%s", si->mime) == -1)
+ return -1;
+ }
+ return 1;
+ }
+ return -1;
+}
+
+protected int
+file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
+ size_t nbytes)
+{
+ cdf_info_t info;
+ cdf_header_t h;
+ cdf_sat_t sat, ssat;
+ cdf_stream_t sst, scn;
+ cdf_dir_t dir;
+ int i;
+ const char *expn = "";
+ const cdf_directory_t *root_storage;
+
+ scn.sst_tab = NULL;
+ info.i_fd = fd;
+ info.i_buf = buf;
+ info.i_len = nbytes;
+ if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
+ return 0;
+ if (cdf_read_header(&info, &h) == -1)
+ return 0;
+#ifdef CDF_DEBUG
+ cdf_dump_header(&h);
+#endif
+
+ if ((i = cdf_read_sat(&info, &h, &sat)) == -1) {
+ expn = "Can't read SAT";
+ goto out0;
+ }
+#ifdef CDF_DEBUG
+ cdf_dump_sat("SAT", &sat, CDF_SEC_SIZE(&h));
+#endif
+
+ if ((i = cdf_read_ssat(&info, &h, &sat, &ssat)) == -1) {
+ expn = "Can't read SSAT";
+ goto out1;
+ }
+#ifdef CDF_DEBUG
+ cdf_dump_sat("SSAT", &ssat, CDF_SHORT_SEC_SIZE(&h));
+#endif
+
+ if ((i = cdf_read_dir(&info, &h, &sat, &dir)) == -1) {
+ expn = "Can't read directory";
+ goto out2;
+ }
+
+ if ((i = cdf_read_short_stream(&info, &h, &sat, &dir, &sst,
+ &root_storage)) == -1) {
+ expn = "Cannot read short stream";
+ goto out3;
+ }
+#ifdef CDF_DEBUG
+ cdf_dump_dir(&info, &h, &sat, &ssat, &sst, &dir);
+#endif
+#ifdef notdef
+ if (root_storage) {
+ if (NOTMIME(ms)) {
+ char clsbuf[128];
+ if (file_printf(ms, "CLSID %s, ",
+ format_clsid(clsbuf, sizeof(clsbuf),
+ root_storage->d_storage_uuid)) == -1)
+ return -1;
+ }
+ }
+#endif
+
+ if ((i = cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, &dir,
+ "FileHeader", &scn)) != -1) {
+#define HWP5_SIGNATURE "HWP Document File"
+ if (scn.sst_len * scn.sst_ss >= sizeof(HWP5_SIGNATURE) - 1
+ && memcmp(scn.sst_tab, HWP5_SIGNATURE,
+ sizeof(HWP5_SIGNATURE) - 1) == 0) {
+ if (NOTMIME(ms)) {
+ if (file_printf(ms,
+ "Hangul (Korean) Word Processor File 5.x") == -1)
+ return -1;
+ } else {
+ if (file_printf(ms, "application/x-hwp") == -1)
+ return -1;
+ }
+ i = 1;
+ goto out5;
+ } else {
+ cdf_zero_stream(&scn);
+ }
+ }
+
+ if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
+ &scn)) == -1) {
+ if (errno != ESRCH) {
+ expn = "Cannot read summary info";
+ }
+ } else {
+ i = cdf_check_summary_info(ms, &info, &h,
+ &sat, &ssat, &sst, &dir, &scn, root_storage, &expn);
+ cdf_zero_stream(&scn);
+ }
+ if (i <= 0) {
+ if ((i = cdf_read_doc_summary_info(&info, &h, &sat, &ssat,
+ &sst, &dir, &scn)) == -1) {
+ if (errno != ESRCH) {
+ expn = "Cannot read summary info";
+ }
+ } else {
+ i = cdf_check_summary_info(ms, &info, &h, &sat, &ssat,
+ &sst, &dir, &scn, root_storage, &expn);
+ }
+ }
+ if (i <= 0) {
+ i = cdf_file_dir_info(ms, &dir);
+ if (i < 0)
+ expn = "Cannot read section info";
+ }
+out5:
+ cdf_zero_stream(&scn);
+ cdf_zero_stream(&sst);
+out3:
+ free(dir.dir_tab);
+out2:
+ free(ssat.sat_tab);
+out1:
+ free(sat.sat_tab);
+out0:
+ if (i == -1) {
+ if (NOTMIME(ms)) {
+ if (file_printf(ms,
+ "Composite Document File V2 Document") == -1)
+ return -1;
+ if (*expn)
+ if (file_printf(ms, ", %s", expn) == -1)
+ return -1;
+ } else {
+ if (file_printf(ms, "application/CDFV2") == -1)
+ return -1;
+ }
+ i = 1;
+ }
+ return i;
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/readelf.c b/node_modules/mmmagic/deps/libmagic/src/readelf.c
new file mode 100644
index 0000000..5f425c9
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/readelf.c
@@ -0,0 +1,1640 @@
+/*
+ * Copyright (c) Christos Zoulas 2003.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: readelf.c,v 1.138 2017/08/27 07:55:02 christos Exp $")
+#endif
+
+#ifdef BUILTIN_ELF
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "readelf.h"
+#include "magic.h"
+
+#ifdef ELFCORE
+private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
+ off_t, int *, uint16_t *);
+#endif
+private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
+ off_t, int, int *, uint16_t *);
+private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
+ off_t, int, int, int *, uint16_t *);
+private size_t donote(struct magic_set *, void *, size_t, size_t, int,
+ int, size_t, int *, uint16_t *, int, off_t, int, off_t);
+
+#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align)
+
+#define isquote(c) (strchr("'\"`", (c)) != NULL)
+
+private uint16_t getu16(int, uint16_t);
+private uint32_t getu32(int, uint32_t);
+private uint64_t getu64(int, uint64_t);
+
+#define MAX_PHNUM 128
+#define MAX_SHNUM 32768
+#define SIZE_UNKNOWN ((off_t)-1)
+
+private int
+toomany(struct magic_set *ms, const char *name, uint16_t num)
+{
+ if (file_printf(ms, ", too many %s (%u)", name, num
+ ) == -1)
+ return -1;
+ return 0;
+}
+
+private uint16_t
+getu16(int swap, uint16_t value)
+{
+ union {
+ uint16_t ui;
+ char c[2];
+ } retval, tmpval;
+
+ if (swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[1];
+ retval.c[1] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+
+private uint32_t
+getu32(int swap, uint32_t value)
+{
+ union {
+ uint32_t ui;
+ char c[4];
+ } retval, tmpval;
+
+ if (swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[3];
+ retval.c[1] = tmpval.c[2];
+ retval.c[2] = tmpval.c[1];
+ retval.c[3] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+
+private uint64_t
+getu64(int swap, uint64_t value)
+{
+ union {
+ uint64_t ui;
+ char c[8];
+ } retval, tmpval;
+
+ if (swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[7];
+ retval.c[1] = tmpval.c[6];
+ retval.c[2] = tmpval.c[5];
+ retval.c[3] = tmpval.c[4];
+ retval.c[4] = tmpval.c[3];
+ retval.c[5] = tmpval.c[2];
+ retval.c[6] = tmpval.c[1];
+ retval.c[7] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+
+#define elf_getu16(swap, value) getu16(swap, value)
+#define elf_getu32(swap, value) getu32(swap, value)
+#define elf_getu64(swap, value) getu64(swap, value)
+
+#define xsh_addr (clazz == ELFCLASS32 \
+ ? (void *)&sh32 \
+ : (void *)&sh64)
+#define xsh_sizeof (clazz == ELFCLASS32 \
+ ? sizeof(sh32) \
+ : sizeof(sh64))
+#define xsh_size (size_t)(clazz == ELFCLASS32 \
+ ? elf_getu32(swap, sh32.sh_size) \
+ : elf_getu64(swap, sh64.sh_size))
+#define xsh_offset (off_t)(clazz == ELFCLASS32 \
+ ? elf_getu32(swap, sh32.sh_offset) \
+ : elf_getu64(swap, sh64.sh_offset))
+#define xsh_type (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, sh32.sh_type) \
+ : elf_getu32(swap, sh64.sh_type))
+#define xsh_name (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, sh32.sh_name) \
+ : elf_getu32(swap, sh64.sh_name))
+#define xph_addr (clazz == ELFCLASS32 \
+ ? (void *) &ph32 \
+ : (void *) &ph64)
+#define xph_sizeof (clazz == ELFCLASS32 \
+ ? sizeof(ph32) \
+ : sizeof(ph64))
+#define xph_type (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, ph32.p_type) \
+ : elf_getu32(swap, ph64.p_type))
+#define xph_offset (off_t)(clazz == ELFCLASS32 \
+ ? elf_getu32(swap, ph32.p_offset) \
+ : elf_getu64(swap, ph64.p_offset))
+#define xph_align (size_t)((clazz == ELFCLASS32 \
+ ? (off_t) (ph32.p_align ? \
+ elf_getu32(swap, ph32.p_align) : 4) \
+ : (off_t) (ph64.p_align ? \
+ elf_getu64(swap, ph64.p_align) : 4)))
+#define xph_vaddr (size_t)((clazz == ELFCLASS32 \
+ ? (off_t) (ph32.p_vaddr ? \
+ elf_getu32(swap, ph32.p_vaddr) : 4) \
+ : (off_t) (ph64.p_vaddr ? \
+ elf_getu64(swap, ph64.p_vaddr) : 4)))
+#define xph_filesz (size_t)((clazz == ELFCLASS32 \
+ ? elf_getu32(swap, ph32.p_filesz) \
+ : elf_getu64(swap, ph64.p_filesz)))
+#define xnh_addr (clazz == ELFCLASS32 \
+ ? (void *)&nh32 \
+ : (void *)&nh64)
+#define xph_memsz (size_t)((clazz == ELFCLASS32 \
+ ? elf_getu32(swap, ph32.p_memsz) \
+ : elf_getu64(swap, ph64.p_memsz)))
+#define xnh_sizeof (clazz == ELFCLASS32 \
+ ? sizeof(nh32) \
+ : sizeof(nh64))
+#define xnh_type (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, nh32.n_type) \
+ : elf_getu32(swap, nh64.n_type))
+#define xnh_namesz (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, nh32.n_namesz) \
+ : elf_getu32(swap, nh64.n_namesz))
+#define xnh_descsz (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, nh32.n_descsz) \
+ : elf_getu32(swap, nh64.n_descsz))
+#define prpsoffsets(i) (clazz == ELFCLASS32 \
+ ? prpsoffsets32[i] \
+ : prpsoffsets64[i])
+#define xcap_addr (clazz == ELFCLASS32 \
+ ? (void *)&cap32 \
+ : (void *)&cap64)
+#define xcap_sizeof (clazz == ELFCLASS32 \
+ ? sizeof cap32 \
+ : sizeof cap64)
+#define xcap_tag (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, cap32.c_tag) \
+ : elf_getu64(swap, cap64.c_tag))
+#define xcap_val (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, cap32.c_un.c_val) \
+ : elf_getu64(swap, cap64.c_un.c_val))
+#define xauxv_addr (clazz == ELFCLASS32 \
+ ? (void *)&auxv32 \
+ : (void *)&auxv64)
+#define xauxv_sizeof (clazz == ELFCLASS32 \
+ ? sizeof(auxv32) \
+ : sizeof(auxv64))
+#define xauxv_type (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, auxv32.a_type) \
+ : elf_getu64(swap, auxv64.a_type))
+#define xauxv_val (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, auxv32.a_v) \
+ : elf_getu64(swap, auxv64.a_v))
+
+#ifdef ELFCORE
+/*
+ * Try larger offsets first to avoid false matches
+ * from earlier data that happen to look like strings.
+ */
+static const size_t prpsoffsets32[] = {
+#ifdef USE_NT_PSINFO
+ 104, /* SunOS 5.x (command line) */
+ 88, /* SunOS 5.x (short name) */
+#endif /* USE_NT_PSINFO */
+
+ 100, /* SunOS 5.x (command line) */
+ 84, /* SunOS 5.x (short name) */
+
+ 44, /* Linux (command line) */
+ 28, /* Linux 2.0.36 (short name) */
+
+ 8, /* FreeBSD */
+};
+
+static const size_t prpsoffsets64[] = {
+#ifdef USE_NT_PSINFO
+ 152, /* SunOS 5.x (command line) */
+ 136, /* SunOS 5.x (short name) */
+#endif /* USE_NT_PSINFO */
+
+ 136, /* SunOS 5.x, 64-bit (command line) */
+ 120, /* SunOS 5.x, 64-bit (short name) */
+
+ 56, /* Linux (command line) */
+ 40, /* Linux (tested on core from 2.4.x, short name) */
+
+ 16, /* FreeBSD, 64-bit */
+};
+
+#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
+#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
+
+#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
+ * "FreeBSD"; if one is found, try looking in various places in its
+ * contents for a 16-character string containing only printable
+ * characters - if found, that string should be the name of the program
+ * that dropped core. Note: right after that 16-character string is,
+ * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
+ * Linux, a longer string (80 characters, in 5.x, probably other
+ * SVR4-flavored systems, and Linux) containing the start of the
+ * command line for that program.
+ *
+ * SunOS 5.x core files contain two PT_NOTE sections, with the types
+ * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the
+ * same info about the command name and command line, so it probably
+ * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
+ * above (see USE_NT_PSINFO), in case we ever decide to do so. The
+ * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
+ * the SunOS 5.x file command relies on this (and prefers the latter).
+ *
+ * The signal number probably appears in a section of type NT_PRSTATUS,
+ * but that's also rather OS-dependent, in ways that are harder to
+ * dissect with heuristics, so I'm not bothering with the signal number.
+ * (I suppose the signal number could be of interest in situations where
+ * you don't have the binary of the program that dropped core; if you
+ * *do* have that binary, the debugger will probably tell you what
+ * signal it was.)
+ */
+
+#define OS_STYLE_SVR4 0
+#define OS_STYLE_FREEBSD 1
+#define OS_STYLE_NETBSD 2
+
+private const char os_style_names[][8] = {
+ "SVR4",
+ "FreeBSD",
+ "NetBSD",
+};
+
+#define FLAGS_CORE_STYLE 0x003
+
+#define FLAGS_DID_CORE 0x004
+#define FLAGS_DID_OS_NOTE 0x008
+#define FLAGS_DID_BUILD_ID 0x010
+#define FLAGS_DID_CORE_STYLE 0x020
+#define FLAGS_DID_NETBSD_PAX 0x040
+#define FLAGS_DID_NETBSD_MARCH 0x080
+#define FLAGS_DID_NETBSD_CMODEL 0x100
+#define FLAGS_DID_NETBSD_UNKNOWN 0x200
+#define FLAGS_IS_CORE 0x400
+#define FLAGS_DID_AUXV 0x800
+
+private int
+dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
+{
+ Elf32_Phdr ph32;
+ Elf64_Phdr ph64;
+ size_t offset, len;
+ unsigned char nbuf[BUFSIZ];
+ ssize_t bufsize;
+ off_t ph_off = off;
+ int ph_num = num;
+
+ if (size != xph_sizeof) {
+ if (file_printf(ms, ", corrupted program header size") == -1)
+ return -1;
+ return 0;
+ }
+
+ /*
+ * Loop through all the program headers.
+ */
+ for ( ; num; num--) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+ off += size;
+
+ if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ /* Perhaps warn here */
+ continue;
+ }
+
+ if (xph_type != PT_NOTE)
+ continue;
+
+ /*
+ * This is a PT_NOTE section; loop through all the notes
+ * in the section.
+ */
+ len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
+ if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
+ file_badread(ms);
+ return -1;
+ }
+ offset = 0;
+ for (;;) {
+ if (offset >= (size_t)bufsize)
+ break;
+ offset = donote(ms, nbuf, offset, (size_t)bufsize,
+ clazz, swap, 4, flags, notecount, fd, ph_off,
+ ph_num, fsize);
+ if (offset == 0)
+ break;
+
+ }
+ }
+ return 0;
+}
+#endif
+
+static void
+do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
+{
+ uint32_t desc;
+ (void)memcpy(&desc, v, sizeof(desc));
+ desc = elf_getu32(swap, desc);
+
+ if (file_printf(ms, ", for NetBSD") == -1)
+ return;
+ /*
+ * The version number used to be stuck as 199905, and was thus
+ * basically content-free. Newer versions of NetBSD have fixed
+ * this and now use the encoding of __NetBSD_Version__:
+ *
+ * MMmmrrpp00
+ *
+ * M = major version
+ * m = minor version
+ * r = release ["",A-Z,Z[A-Z] but numeric]
+ * p = patchlevel
+ */
+ if (desc > 100000000U) {
+ uint32_t ver_patch = (desc / 100) % 100;
+ uint32_t ver_rel = (desc / 10000) % 100;
+ uint32_t ver_min = (desc / 1000000) % 100;
+ uint32_t ver_maj = desc / 100000000;
+
+ if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
+ return;
+ if (ver_rel == 0 && ver_patch != 0) {
+ if (file_printf(ms, ".%u", ver_patch) == -1)
+ return;
+ } else if (ver_rel != 0) {
+ while (ver_rel > 26) {
+ if (file_printf(ms, "Z") == -1)
+ return;
+ ver_rel -= 26;
+ }
+ if (file_printf(ms, "%c", 'A' + ver_rel - 1)
+ == -1)
+ return;
+ }
+ }
+}
+
+static void
+do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
+{
+ uint32_t desc;
+
+ (void)memcpy(&desc, v, sizeof(desc));
+ desc = elf_getu32(swap, desc);
+ if (file_printf(ms, ", for FreeBSD") == -1)
+ return;
+
+ /*
+ * Contents is __FreeBSD_version, whose relation to OS
+ * versions is defined by a huge table in the Porter's
+ * Handbook. This is the general scheme:
+ *
+ * Releases:
+ * Mmp000 (before 4.10)
+ * Mmi0p0 (before 5.0)
+ * Mmm0p0
+ *
+ * Development branches:
+ * Mmpxxx (before 4.6)
+ * Mmp1xx (before 4.10)
+ * Mmi1xx (before 5.0)
+ * M000xx (pre-M.0)
+ * Mmm1xx
+ *
+ * M = major version
+ * m = minor version
+ * i = minor version increment (491000 -> 4.10)
+ * p = patchlevel
+ * x = revision
+ *
+ * The first release of FreeBSD to use ELF by default
+ * was version 3.0.
+ */
+ if (desc == 460002) {
+ if (file_printf(ms, " 4.6.2") == -1)
+ return;
+ } else if (desc < 460100) {
+ if (file_printf(ms, " %d.%d", desc / 100000,
+ desc / 10000 % 10) == -1)
+ return;
+ if (desc / 1000 % 10 > 0)
+ if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
+ return;
+ if ((desc % 1000 > 0) || (desc % 100000 == 0))
+ if (file_printf(ms, " (%d)", desc) == -1)
+ return;
+ } else if (desc < 500000) {
+ if (file_printf(ms, " %d.%d", desc / 100000,
+ desc / 10000 % 10 + desc / 1000 % 10) == -1)
+ return;
+ if (desc / 100 % 10 > 0) {
+ if (file_printf(ms, " (%d)", desc) == -1)
+ return;
+ } else if (desc / 10 % 10 > 0) {
+ if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
+ return;
+ }
+ } else {
+ if (file_printf(ms, " %d.%d", desc / 100000,
+ desc / 1000 % 100) == -1)
+ return;
+ if ((desc / 100 % 10 > 0) ||
+ (desc % 100000 / 100 == 0)) {
+ if (file_printf(ms, " (%d)", desc) == -1)
+ return;
+ } else if (desc / 10 % 10 > 0) {
+ if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
+ return;
+ }
+ }
+}
+
+private int
+/*ARGSUSED*/
+do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
+{
+ if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+ type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) {
+ uint8_t desc[20];
+ const char *btype;
+ uint32_t i;
+ *flags |= FLAGS_DID_BUILD_ID;
+ switch (descsz) {
+ case 8:
+ btype = "xxHash";
+ break;
+ case 16:
+ btype = "md5/uuid";
+ break;
+ case 20:
+ btype = "sha1";
+ break;
+ default:
+ btype = "unknown";
+ break;
+ }
+ if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
+ return 1;
+ (void)memcpy(desc, &nbuf[doff], descsz);
+ for (i = 0; i < descsz; i++)
+ if (file_printf(ms, "%02x", desc[i]) == -1)
+ return 1;
+ return 1;
+ }
+ return 0;
+}
+
+private int
+do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
+{
+ if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 &&
+ type == NT_GNU_VERSION && descsz == 2) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]);
+ return 1;
+ }
+
+ if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
+ type == NT_GNU_VERSION && descsz == 16) {
+ uint32_t desc[4];
+ (void)memcpy(desc, &nbuf[doff], sizeof(desc));
+
+ *flags |= FLAGS_DID_OS_NOTE;
+ if (file_printf(ms, ", for GNU/") == -1)
+ return 1;
+ switch (elf_getu32(swap, desc[0])) {
+ case GNU_OS_LINUX:
+ if (file_printf(ms, "Linux") == -1)
+ return 1;
+ break;
+ case GNU_OS_HURD:
+ if (file_printf(ms, "Hurd") == -1)
+ return 1;
+ break;
+ case GNU_OS_SOLARIS:
+ if (file_printf(ms, "Solaris") == -1)
+ return 1;
+ break;
+ case GNU_OS_KFREEBSD:
+ if (file_printf(ms, "kFreeBSD") == -1)
+ return 1;
+ break;
+ case GNU_OS_KNETBSD:
+ if (file_printf(ms, "kNetBSD") == -1)
+ return 1;
+ break;
+ default:
+ if (file_printf(ms, "<unknown>") == -1)
+ return 1;
+ }
+ if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
+ elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
+ return 1;
+ return 1;
+ }
+
+ if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+ if (type == NT_NETBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ do_note_netbsd_version(ms, swap, &nbuf[doff]);
+ return 1;
+ }
+ }
+
+ if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) {
+ if (type == NT_FREEBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ do_note_freebsd_version(ms, swap, &nbuf[doff]);
+ return 1;
+ }
+ }
+
+ if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
+ type == NT_OPENBSD_VERSION && descsz == 4) {
+ *flags |= FLAGS_DID_OS_NOTE;
+ if (file_printf(ms, ", for OpenBSD") == -1)
+ return 1;
+ /* Content of note is always 0 */
+ return 1;
+ }
+
+ if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
+ type == NT_DRAGONFLY_VERSION && descsz == 4) {
+ uint32_t desc;
+ *flags |= FLAGS_DID_OS_NOTE;
+ if (file_printf(ms, ", for DragonFly") == -1)
+ return 1;
+ (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+ desc = elf_getu32(swap, desc);
+ if (file_printf(ms, " %d.%d.%d", desc / 100000,
+ desc / 10000 % 10, desc % 10000) == -1)
+ return 1;
+ return 1;
+ }
+ return 0;
+}
+
+private int
+do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags)
+{
+ if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 &&
+ type == NT_NETBSD_PAX && descsz == 4) {
+ static const char *pax[] = {
+ "+mprotect",
+ "-mprotect",
+ "+segvguard",
+ "-segvguard",
+ "+ASLR",
+ "-ASLR",
+ };
+ uint32_t desc;
+ size_t i;
+ int did = 0;
+
+ *flags |= FLAGS_DID_NETBSD_PAX;
+ (void)memcpy(&desc, &nbuf[doff], sizeof(desc));
+ desc = elf_getu32(swap, desc);
+
+ if (desc && file_printf(ms, ", PaX: ") == -1)
+ return 1;
+
+ for (i = 0; i < __arraycount(pax); i++) {
+ if (((1 << (int)i) & desc) == 0)
+ continue;
+ if (file_printf(ms, "%s%s", did++ ? "," : "",
+ pax[i]) == -1)
+ return 1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+private int
+do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz, uint32_t descsz,
+ size_t noff, size_t doff, int *flags, size_t size, int clazz)
+{
+#ifdef ELFCORE
+ int os_style = -1;
+ /*
+ * Sigh. The 2.0.36 kernel in Debian 2.1, at
+ * least, doesn't correctly implement name
+ * sections, in core dumps, as specified by
+ * the "Program Linking" section of "UNIX(R) System
+ * V Release 4 Programmer's Guide: ANSI C and
+ * Programming Support Tools", because my copy
+ * clearly says "The first 'namesz' bytes in 'name'
+ * contain a *null-terminated* [emphasis mine]
+ * character representation of the entry's owner
+ * or originator", but the 2.0.36 kernel code
+ * doesn't include the terminating null in the
+ * name....
+ */
+ if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
+ (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
+ os_style = OS_STYLE_SVR4;
+ }
+
+ if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
+ os_style = OS_STYLE_FREEBSD;
+ }
+
+ if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
+ == 0)) {
+ os_style = OS_STYLE_NETBSD;
+ }
+
+ if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
+ if (file_printf(ms, ", %s-style", os_style_names[os_style])
+ == -1)
+ return 1;
+ *flags |= FLAGS_DID_CORE_STYLE;
+ *flags |= os_style;
+ }
+
+ switch (os_style) {
+ case OS_STYLE_NETBSD:
+ if (type == NT_NETBSD_CORE_PROCINFO) {
+ char sbuf[512];
+ struct NetBSD_elfcore_procinfo pi;
+ memset(&pi, 0, sizeof(pi));
+ memcpy(&pi, nbuf + doff, descsz);
+
+ if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
+ "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)",
+ file_printable(sbuf, sizeof(sbuf),
+ CAST(char *, pi.cpi_name)),
+ elf_getu32(swap, pi.cpi_pid),
+ elf_getu32(swap, pi.cpi_euid),
+ elf_getu32(swap, pi.cpi_egid),
+ elf_getu32(swap, pi.cpi_nlwps),
+ elf_getu32(swap, pi.cpi_siglwp),
+ elf_getu32(swap, pi.cpi_signo),
+ elf_getu32(swap, pi.cpi_sigcode)) == -1)
+ return 1;
+
+ *flags |= FLAGS_DID_CORE;
+ return 1;
+ }
+ break;
+
+ default:
+ if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
+ size_t i, j;
+ unsigned char c;
+ /*
+ * Extract the program name. We assume
+ * it to be 16 characters (that's what it
+ * is in SunOS 5.x and Linux).
+ *
+ * Unfortunately, it's at a different offset
+ * in various OSes, so try multiple offsets.
+ * If the characters aren't all printable,
+ * reject it.
+ */
+ for (i = 0; i < NOFFSETS; i++) {
+ unsigned char *cname, *cp;
+ size_t reloffset = prpsoffsets(i);
+ size_t noffset = doff + reloffset;
+ size_t k;
+ for (j = 0; j < 16; j++, noffset++,
+ reloffset++) {
+ /*
+ * Make sure we're not past
+ * the end of the buffer; if
+ * we are, just give up.
+ */
+ if (noffset >= size)
+ goto tryanother;
+
+ /*
+ * Make sure we're not past
+ * the end of the contents;
+ * if we are, this obviously
+ * isn't the right offset.
+ */
+ if (reloffset >= descsz)
+ goto tryanother;
+
+ c = nbuf[noffset];
+ if (c == '\0') {
+ /*
+ * A '\0' at the
+ * beginning is
+ * obviously wrong.
+ * Any other '\0'
+ * means we're done.
+ */
+ if (j == 0)
+ goto tryanother;
+ else
+ break;
+ } else {
+ /*
+ * A nonprintable
+ * character is also
+ * wrong.
+ */
+ if (!isprint(c) || isquote(c))
+ goto tryanother;
+ }
+ }
+ /*
+ * Well, that worked.
+ */
+
+ /*
+ * Try next offsets, in case this match is
+ * in the middle of a string.
+ */
+ for (k = i + 1 ; k < NOFFSETS; k++) {
+ size_t no;
+ int adjust = 1;
+ if (prpsoffsets(k) >= prpsoffsets(i))
+ continue;
+ for (no = doff + prpsoffsets(k);
+ no < doff + prpsoffsets(i); no++)
+ adjust = adjust
+ && isprint(nbuf[no]);
+ if (adjust)
+ i = k;
+ }
+
+ cname = (unsigned char *)
+ &nbuf[doff + prpsoffsets(i)];
+ for (cp = cname; *cp && isprint(*cp); cp++)
+ continue;
+ /*
+ * Linux apparently appends a space at the end
+ * of the command line: remove it.
+ */
+ while (cp > cname && isspace(cp[-1]))
+ cp--;
+ if (file_printf(ms, ", from '%.*s'",
+ (int)(cp - cname), cname) == -1)
+ return 1;
+ *flags |= FLAGS_DID_CORE;
+ return 1;
+
+ tryanother:
+ ;
+ }
+ }
+ break;
+ }
+#endif
+ return 0;
+}
+
+private off_t
+get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
+ off_t off, int num, off_t fsize, uint64_t virtaddr)
+{
+ Elf32_Phdr ph32;
+ Elf64_Phdr ph64;
+
+ /*
+ * Loop through all the program headers and find the header with
+ * virtual address in which the "virtaddr" belongs to.
+ */
+ for ( ; num; num--) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+ off += xph_sizeof;
+
+ if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ /* Perhaps warn here */
+ continue;
+ }
+
+ if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
+ return xph_offset + (virtaddr - xph_vaddr);
+ }
+ return 0;
+}
+
+private size_t
+get_string_on_virtaddr(struct magic_set *ms,
+ int swap, int clazz, int fd, off_t ph_off, int ph_num,
+ off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
+{
+ char *bptr;
+ off_t offset;
+
+ if (buflen == 0)
+ return 0;
+
+ offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
+ fsize, virtaddr);
+ if ((buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) {
+ file_badread(ms);
+ return 0;
+ }
+
+ buf[buflen - 1] = '\0';
+
+ /* We expect only printable characters, so return if buffer contains
+ * non-printable character before the '\0' or just '\0'. */
+ for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++)
+ continue;
+ if (*bptr != '\0')
+ return 0;
+
+ return bptr - buf;
+}
+
+
+private int
+do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz __attribute__((__unused__)),
+ uint32_t descsz __attribute__((__unused__)),
+ size_t noff __attribute__((__unused__)), size_t doff,
+ int *flags, size_t size __attribute__((__unused__)), int clazz,
+ int fd, off_t ph_off, int ph_num, off_t fsize)
+{
+#ifdef ELFCORE
+ Aux32Info auxv32;
+ Aux64Info auxv64;
+ size_t elsize = xauxv_sizeof;
+ const char *tag;
+ int is_string;
+ size_t nval;
+
+ if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) !=
+ (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE))
+ return 0;
+
+ switch (*flags & FLAGS_CORE_STYLE) {
+ case OS_STYLE_SVR4:
+ if (type != NT_AUXV)
+ return 0;
+ break;
+#ifdef notyet
+ case OS_STYLE_NETBSD:
+ if (type != NT_NETBSD_CORE_AUXV)
+ return 0;
+ break;
+ case OS_STYLE_FREEBSD:
+ if (type != NT_FREEBSD_PROCSTAT_AUXV)
+ return 0;
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ *flags |= FLAGS_DID_AUXV;
+
+ nval = 0;
+ for (size_t off = 0; off + elsize <= descsz; off += elsize) {
+ (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
+ /* Limit processing to 50 vector entries to prevent DoS */
+ if (nval++ >= 50) {
+ file_error(ms, 0, "Too many ELF Auxv elements");
+ return 1;
+ }
+
+ switch(xauxv_type) {
+ case AT_LINUX_EXECFN:
+ is_string = 1;
+ tag = "execfn";
+ break;
+ case AT_LINUX_PLATFORM:
+ is_string = 1;
+ tag = "platform";
+ break;
+ case AT_LINUX_UID:
+ is_string = 0;
+ tag = "real uid";
+ break;
+ case AT_LINUX_GID:
+ is_string = 0;
+ tag = "real gid";
+ break;
+ case AT_LINUX_EUID:
+ is_string = 0;
+ tag = "effective uid";
+ break;
+ case AT_LINUX_EGID:
+ is_string = 0;
+ tag = "effective gid";
+ break;
+ default:
+ is_string = 0;
+ tag = NULL;
+ break;
+ }
+
+ if (tag == NULL)
+ continue;
+
+ if (is_string) {
+ char buf[256];
+ ssize_t buflen;
+ buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
+ ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
+
+ if (buflen == 0)
+ continue;
+
+ if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
+ return 0;
+ } else {
+ if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val)
+ == -1)
+ return 0;
+ }
+ }
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+private size_t
+donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
+ int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
+ int fd, off_t ph_off, int ph_num, off_t fsize)
+{
+ Elf32_Nhdr nh32;
+ Elf64_Nhdr nh64;
+ size_t noff, doff;
+ uint32_t namesz, descsz;
+ unsigned char *nbuf = CAST(unsigned char *, vbuf);
+
+ if (*notecount == 0)
+ return 0;
+ --*notecount;
+
+ if (xnh_sizeof + offset > size) {
+ /*
+ * We're out of note headers.
+ */
+ return xnh_sizeof + offset;
+ }
+
+ (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
+ offset += xnh_sizeof;
+
+ namesz = xnh_namesz;
+ descsz = xnh_descsz;
+
+ if ((namesz == 0) && (descsz == 0)) {
+ /*
+ * We're out of note headers.
+ */
+ return (offset >= size) ? offset : size;
+ }
+
+ if (namesz & 0x80000000) {
+ (void)file_printf(ms, ", bad note name size %#lx",
+ (unsigned long)namesz);
+ return 0;
+ }
+
+ if (descsz & 0x80000000) {
+ (void)file_printf(ms, ", bad note description size %#lx",
+ (unsigned long)descsz);
+ return 0;
+ }
+
+ noff = offset;
+ doff = ELF_ALIGN(offset + namesz);
+
+ if (offset + namesz > size) {
+ /*
+ * We're past the end of the buffer.
+ */
+ return doff;
+ }
+
+ offset = ELF_ALIGN(doff + descsz);
+ if (doff + descsz > size) {
+ /*
+ * We're past the end of the buffer.
+ */
+ return (offset >= size) ? offset : size;
+ }
+
+
+ if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
+ if (do_os_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return offset;
+ }
+
+ if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
+ if (do_bid_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return offset;
+ }
+
+ if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
+ if (do_pax_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags))
+ return offset;
+ }
+
+ if ((*flags & FLAGS_DID_CORE) == 0) {
+ if (do_core_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags, size, clazz))
+ return offset;
+ }
+
+ if ((*flags & FLAGS_DID_AUXV) == 0) {
+ if (do_auxv_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags, size, clazz,
+ fd, ph_off, ph_num, fsize))
+ return offset;
+ }
+
+ if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
+ if (descsz > 100)
+ descsz = 100;
+ switch (xnh_type) {
+ case NT_NETBSD_VERSION:
+ return offset;
+ case NT_NETBSD_MARCH:
+ if (*flags & FLAGS_DID_NETBSD_MARCH)
+ return offset;
+ *flags |= FLAGS_DID_NETBSD_MARCH;
+ if (file_printf(ms, ", compiled for: %.*s",
+ (int)descsz, (const char *)&nbuf[doff]) == -1)
+ return offset;
+ break;
+ case NT_NETBSD_CMODEL:
+ if (*flags & FLAGS_DID_NETBSD_CMODEL)
+ return offset;
+ *flags |= FLAGS_DID_NETBSD_CMODEL;
+ if (file_printf(ms, ", compiler model: %.*s",
+ (int)descsz, (const char *)&nbuf[doff]) == -1)
+ return offset;
+ break;
+ default:
+ if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
+ return offset;
+ *flags |= FLAGS_DID_NETBSD_UNKNOWN;
+ if (file_printf(ms, ", note=%u", xnh_type) == -1)
+ return offset;
+ break;
+ }
+ return offset;
+ }
+
+ return offset;
+}
+
+/* SunOS 5.x hardware capability descriptions */
+typedef struct cap_desc {
+ uint64_t cd_mask;
+ const char *cd_name;
+} cap_desc_t;
+
+static const cap_desc_t cap_desc_sparc[] = {
+ { AV_SPARC_MUL32, "MUL32" },
+ { AV_SPARC_DIV32, "DIV32" },
+ { AV_SPARC_FSMULD, "FSMULD" },
+ { AV_SPARC_V8PLUS, "V8PLUS" },
+ { AV_SPARC_POPC, "POPC" },
+ { AV_SPARC_VIS, "VIS" },
+ { AV_SPARC_VIS2, "VIS2" },
+ { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" },
+ { AV_SPARC_FMAF, "FMAF" },
+ { AV_SPARC_FJFMAU, "FJFMAU" },
+ { AV_SPARC_IMA, "IMA" },
+ { 0, NULL }
+};
+
+static const cap_desc_t cap_desc_386[] = {
+ { AV_386_FPU, "FPU" },
+ { AV_386_TSC, "TSC" },
+ { AV_386_CX8, "CX8" },
+ { AV_386_SEP, "SEP" },
+ { AV_386_AMD_SYSC, "AMD_SYSC" },
+ { AV_386_CMOV, "CMOV" },
+ { AV_386_MMX, "MMX" },
+ { AV_386_AMD_MMX, "AMD_MMX" },
+ { AV_386_AMD_3DNow, "AMD_3DNow" },
+ { AV_386_AMD_3DNowx, "AMD_3DNowx" },
+ { AV_386_FXSR, "FXSR" },
+ { AV_386_SSE, "SSE" },
+ { AV_386_SSE2, "SSE2" },
+ { AV_386_PAUSE, "PAUSE" },
+ { AV_386_SSE3, "SSE3" },
+ { AV_386_MON, "MON" },
+ { AV_386_CX16, "CX16" },
+ { AV_386_AHF, "AHF" },
+ { AV_386_TSCP, "TSCP" },
+ { AV_386_AMD_SSE4A, "AMD_SSE4A" },
+ { AV_386_POPCNT, "POPCNT" },
+ { AV_386_AMD_LZCNT, "AMD_LZCNT" },
+ { AV_386_SSSE3, "SSSE3" },
+ { AV_386_SSE4_1, "SSE4.1" },
+ { AV_386_SSE4_2, "SSE4.2" },
+ { 0, NULL }
+};
+
+private int
+doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
+ size_t size, off_t fsize, int mach, int strtab, int *flags,
+ uint16_t *notecount)
+{
+ Elf32_Shdr sh32;
+ Elf64_Shdr sh64;
+ int stripped = 1, has_debug_info = 0;
+ size_t nbadcap = 0;
+ void *nbuf;
+ off_t noff, coff, name_off;
+ uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilities */
+ uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilities */
+ char name[50];
+ ssize_t namesize;
+
+ if (size != xsh_sizeof) {
+ if (file_printf(ms, ", corrupted section header size") == -1)
+ return -1;
+ return 0;
+ }
+
+ /* Read offset of name section to be able to read section names later */
+ if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
+ < (ssize_t)xsh_sizeof) {
+ if (file_printf(ms, ", missing section headers") == -1)
+ return -1;
+ return 0;
+ }
+ name_off = xsh_offset;
+
+ for ( ; num; num--) {
+ /* Read the name of this section. */
+ if ((namesize = pread(fd, name, sizeof(name) - 1, name_off + xsh_name)) == -1) {
+ file_badread(ms);
+ return -1;
+ }
+ name[namesize] = '\0';
+ if (strcmp(name, ".debug_info") == 0) {
+ has_debug_info = 1;
+ stripped = 0;
+ }
+
+ if (pread(fd, xsh_addr, xsh_sizeof, off) < (ssize_t)xsh_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+ off += size;
+
+ /* Things we can determine before we seek */
+ switch (xsh_type) {
+ case SHT_SYMTAB:
+#if 0
+ case SHT_DYNSYM:
+#endif
+ stripped = 0;
+ break;
+ default:
+ if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
+ /* Perhaps warn here */
+ continue;
+ }
+ break;
+ }
+
+
+ /* Things we can determine when we seek */
+ switch (xsh_type) {
+ case SHT_NOTE:
+ if ((uintmax_t)(xsh_size + xsh_offset) >
+ (uintmax_t)fsize) {
+ if (file_printf(ms,
+ ", note offset/size %#" INTMAX_T_FORMAT
+ "x+%#" INTMAX_T_FORMAT "x exceeds"
+ " file size %#" INTMAX_T_FORMAT "x",
+ (uintmax_t)xsh_offset, (uintmax_t)xsh_size,
+ (uintmax_t)fsize) == -1)
+ return -1;
+ return 0;
+ }
+ if ((nbuf = malloc(xsh_size)) == NULL) {
+ file_error(ms, errno, "Cannot allocate memory"
+ " for note");
+ return -1;
+ }
+ if (pread(fd, nbuf, xsh_size, xsh_offset) <
+ (ssize_t)xsh_size) {
+ file_badread(ms);
+ free(nbuf);
+ return -1;
+ }
+
+ noff = 0;
+ for (;;) {
+ if (noff >= (off_t)xsh_size)
+ break;
+ noff = donote(ms, nbuf, (size_t)noff,
+ xsh_size, clazz, swap, 4, flags, notecount,
+ fd, 0, 0, 0);
+ if (noff == 0)
+ break;
+ }
+ free(nbuf);
+ break;
+ case SHT_SUNW_cap:
+ switch (mach) {
+ case EM_SPARC:
+ case EM_SPARCV9:
+ case EM_IA_64:
+ case EM_386:
+ case EM_AMD64:
+ break;
+ default:
+ goto skip;
+ }
+
+ if (nbadcap > 5)
+ break;
+ if (lseek(fd, xsh_offset, SEEK_SET) == (off_t)-1) {
+ file_badseek(ms);
+ return -1;
+ }
+ coff = 0;
+ for (;;) {
+ Elf32_Cap cap32;
+ Elf64_Cap cap64;
+ char cbuf[/*CONSTCOND*/
+ MAX(sizeof cap32, sizeof cap64)];
+ if ((coff += xcap_sizeof) > (off_t)xsh_size)
+ break;
+ if (read(fd, cbuf, (size_t)xcap_sizeof) !=
+ (ssize_t)xcap_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+ if (cbuf[0] == 'A') {
+#ifdef notyet
+ char *p = cbuf + 1;
+ uint32_t len, tag;
+ memcpy(&len, p, sizeof(len));
+ p += 4;
+ len = getu32(swap, len);
+ if (memcmp("gnu", p, 3) != 0) {
+ if (file_printf(ms,
+ ", unknown capability %.3s", p)
+ == -1)
+ return -1;
+ break;
+ }
+ p += strlen(p) + 1;
+ tag = *p++;
+ memcpy(&len, p, sizeof(len));
+ p += 4;
+ len = getu32(swap, len);
+ if (tag != 1) {
+ if (file_printf(ms, ", unknown gnu"
+ " capability tag %d", tag)
+ == -1)
+ return -1;
+ break;
+ }
+ // gnu attributes
+#endif
+ break;
+ }
+ (void)memcpy(xcap_addr, cbuf, xcap_sizeof);
+ switch (xcap_tag) {
+ case CA_SUNW_NULL:
+ break;
+ case CA_SUNW_HW_1:
+ cap_hw1 |= xcap_val;
+ break;
+ case CA_SUNW_SF_1:
+ cap_sf1 |= xcap_val;
+ break;
+ default:
+ if (file_printf(ms,
+ ", with unknown capability "
+ "%#" INT64_T_FORMAT "x = %#"
+ INT64_T_FORMAT "x",
+ (unsigned long long)xcap_tag,
+ (unsigned long long)xcap_val) == -1)
+ return -1;
+ if (nbadcap++ > 2)
+ coff = xsh_size;
+ break;
+ }
+ }
+ /*FALLTHROUGH*/
+ skip:
+ default:
+ break;
+ }
+ }
+
+ if (has_debug_info) {
+ if (file_printf(ms, ", with debug_info") == -1)
+ return -1;
+ }
+ if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
+ return -1;
+ if (cap_hw1) {
+ const cap_desc_t *cdp;
+ switch (mach) {
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ cdp = cap_desc_sparc;
+ break;
+ case EM_386:
+ case EM_IA_64:
+ case EM_AMD64:
+ cdp = cap_desc_386;
+ break;
+ default:
+ cdp = NULL;
+ break;
+ }
+ if (file_printf(ms, ", uses") == -1)
+ return -1;
+ if (cdp) {
+ while (cdp->cd_name) {
+ if (cap_hw1 & cdp->cd_mask) {
+ if (file_printf(ms,
+ " %s", cdp->cd_name) == -1)
+ return -1;
+ cap_hw1 &= ~cdp->cd_mask;
+ }
+ ++cdp;
+ }
+ if (cap_hw1)
+ if (file_printf(ms,
+ " unknown hardware capability %#"
+ INT64_T_FORMAT "x",
+ (unsigned long long)cap_hw1) == -1)
+ return -1;
+ } else {
+ if (file_printf(ms,
+ " hardware capability %#" INT64_T_FORMAT "x",
+ (unsigned long long)cap_hw1) == -1)
+ return -1;
+ }
+ }
+ if (cap_sf1) {
+ if (cap_sf1 & SF1_SUNW_FPUSED) {
+ if (file_printf(ms,
+ (cap_sf1 & SF1_SUNW_FPKNWN)
+ ? ", uses frame pointer"
+ : ", not known to use frame pointer") == -1)
+ return -1;
+ }
+ cap_sf1 &= ~SF1_SUNW_MASK;
+ if (cap_sf1)
+ if (file_printf(ms,
+ ", with unknown software capability %#"
+ INT64_T_FORMAT "x",
+ (unsigned long long)cap_sf1) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_INTERP section; if one is found, it's dynamically linked,
+ * otherwise it's statically linked.
+ */
+private int
+dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
+ int num, size_t size, off_t fsize, int sh_num, int *flags,
+ uint16_t *notecount)
+{
+ Elf32_Phdr ph32;
+ Elf64_Phdr ph64;
+ const char *linking_style = "statically";
+ const char *interp = "";
+ unsigned char nbuf[BUFSIZ];
+ char ibuf[BUFSIZ];
+ ssize_t bufsize;
+ size_t offset, align, len;
+
+ if (size != xph_sizeof) {
+ if (file_printf(ms, ", corrupted program header size") == -1)
+ return -1;
+ return 0;
+ }
+
+ for ( ; num; num--) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+
+ off += size;
+ bufsize = 0;
+ align = 4;
+
+ /* Things we can determine before we seek */
+ switch (xph_type) {
+ case PT_DYNAMIC:
+ linking_style = "dynamically";
+ break;
+ case PT_NOTE:
+ if (sh_num) /* Did this through section headers */
+ continue;
+ if (((align = xph_align) & 0x80000000UL) != 0 ||
+ align < 4) {
+ if (file_printf(ms,
+ ", invalid note alignment %#lx",
+ (unsigned long)align) == -1)
+ return -1;
+ align = 4;
+ }
+ /*FALLTHROUGH*/
+ case PT_INTERP:
+ len = xph_filesz < sizeof(nbuf) ? xph_filesz
+ : sizeof(nbuf);
+ bufsize = pread(fd, nbuf, len, xph_offset);
+ if (bufsize == -1) {
+ file_badread(ms);
+ return -1;
+ }
+ break;
+ default:
+ if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ /* Maybe warn here? */
+ continue;
+ }
+ break;
+ }
+
+ /* Things we can determine when we seek */
+ switch (xph_type) {
+ case PT_INTERP:
+ if (bufsize && nbuf[0]) {
+ nbuf[bufsize - 1] = '\0';
+ interp = (const char *)nbuf;
+ } else
+ interp = "*empty*";
+ break;
+ case PT_NOTE:
+ /*
+ * This is a PT_NOTE section; loop through all the notes
+ * in the section.
+ */
+ offset = 0;
+ for (;;) {
+ if (offset >= (size_t)bufsize)
+ break;
+ offset = donote(ms, nbuf, offset,
+ (size_t)bufsize, clazz, swap, align,
+ flags, notecount, fd, 0, 0, 0);
+ if (offset == 0)
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (file_printf(ms, ", %s linked", linking_style)
+ == -1)
+ return -1;
+ if (interp[0])
+ if (file_printf(ms, ", interpreter %s",
+ file_printable(ibuf, sizeof(ibuf), interp)) == -1)
+ return -1;
+ return 0;
+}
+
+
+protected int
+file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
+ size_t nbytes)
+{
+ union {
+ int32_t l;
+ char c[sizeof (int32_t)];
+ } u;
+ int clazz;
+ int swap;
+ struct stat st;
+ off_t fsize;
+ int flags = 0;
+ Elf32_Ehdr elf32hdr;
+ Elf64_Ehdr elf64hdr;
+ uint16_t type, phnum, shnum, notecount;
+
+ if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
+ return 0;
+ /*
+ * ELF executables have multiple section headers in arbitrary
+ * file locations and thus file(1) cannot determine it from easily.
+ * Instead we traverse thru all section headers until a symbol table
+ * one is found or else the binary is stripped.
+ * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
+ */
+ if (buf[EI_MAG0] != ELFMAG0
+ || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
+ || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
+ return 0;
+
+ /*
+ * If we cannot seek, it must be a pipe, socket or fifo.
+ */
+ if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
+ fd = file_pipe2file(ms, fd, buf, nbytes);
+
+ if (fstat(fd, &st) == -1) {
+ file_badread(ms);
+ return -1;
+ }
+ if (S_ISREG(st.st_mode) || st.st_size != 0)
+ fsize = st.st_size;
+ else
+ fsize = SIZE_UNKNOWN;
+
+ clazz = buf[EI_CLASS];
+
+ switch (clazz) {
+ case ELFCLASS32:
+#undef elf_getu
+#define elf_getu(a, b) elf_getu32(a, b)
+#undef elfhdr
+#define elfhdr elf32hdr
+#include "elfclass.h"
+ case ELFCLASS64:
+#undef elf_getu
+#define elf_getu(a, b) elf_getu64(a, b)
+#undef elfhdr
+#define elfhdr elf64hdr
+#include "elfclass.h"
+ default:
+ if (file_printf(ms, ", unknown class %d", clazz) == -1)
+ return -1;
+ break;
+ }
+ return 0;
+}
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/readelf.h b/node_modules/mmmagic/deps/libmagic/src/readelf.h
new file mode 100644
index 0000000..ef880b9
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/readelf.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) Christos Zoulas 2003.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * @(#)Id: readelf.h,v 1.9 2002/05/16 18:45:56 christos Exp
+ *
+ * Provide elf data structures for non-elf machines, allowing file
+ * non-elf hosts to determine if an elf binary is stripped.
+ * Note: cobbled from the linux header file, with modifications
+ */
+#ifndef __fake_elf_h__
+#define __fake_elf_h__
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+typedef uint32_t Elf32_Addr;
+typedef uint32_t Elf32_Off;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef uint8_t Elf32_Char;
+
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Off;
+typedef uint64_t Elf64_Xword;
+typedef uint16_t Elf64_Half;
+typedef uint32_t Elf64_Word;
+typedef uint8_t Elf64_Char;
+
+#define EI_NIDENT 16
+
+typedef struct {
+ Elf32_Word a_type; /* 32-bit id */
+ Elf32_Word a_v; /* 32-bit id */
+} Aux32Info;
+
+typedef struct {
+ Elf64_Xword a_type; /* 64-bit id */
+ Elf64_Xword a_v; /* 64-bit id */
+} Aux64Info;
+
+#define AT_NULL 0 /* end of vector */
+#define AT_IGNORE 1 /* entry should be ignored */
+#define AT_EXECFD 2 /* file descriptor of program */
+#define AT_PHDR 3 /* program headers for program */
+#define AT_PHENT 4 /* size of program header entry */
+#define AT_PHNUM 5 /* number of program headers */
+#define AT_PAGESZ 6 /* system page size */
+#define AT_BASE 7 /* base address of interpreter */
+#define AT_FLAGS 8 /* flags */
+#define AT_ENTRY 9 /* entry point of program */
+#define AT_LINUX_NOTELF 10 /* program is not ELF */
+#define AT_LINUX_UID 11 /* real uid */
+#define AT_LINUX_EUID 12 /* effective uid */
+#define AT_LINUX_GID 13 /* real gid */
+#define AT_LINUX_EGID 14 /* effective gid */
+#define AT_LINUX_PLATFORM 15 /* string identifying CPU for optimizations */
+#define AT_LINUX_HWCAP 16 /* arch dependent hints at CPU capabilities */
+#define AT_LINUX_CLKTCK 17 /* frequency at which times() increments */
+/* AT_* values 18 through 22 are reserved */
+#define AT_LINUX_SECURE 23 /* secure mode boolean */
+#define AT_LINUX_BASE_PLATFORM 24 /* string identifying real platform, may
+ * differ from AT_PLATFORM. */
+#define AT_LINUX_RANDOM 25 /* address of 16 random bytes */
+#define AT_LINUX_HWCAP2 26 /* extension of AT_HWCAP */
+#define AT_LINUX_EXECFN 31 /* filename of program */
+
+typedef struct {
+ Elf32_Char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ Elf64_Char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry; /* Entry point */
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+
+/* e_type */
+#define ET_REL 1
+#define ET_EXEC 2
+#define ET_DYN 3
+#define ET_CORE 4
+
+/* e_machine (used only for SunOS 5.x hardware capabilities) */
+#define EM_SPARC 2
+#define EM_386 3
+#define EM_SPARC32PLUS 18
+#define EM_SPARCV9 43
+#define EM_IA_64 50
+#define EM_AMD64 62
+
+/* sh_type */
+#define SHT_SYMTAB 2
+#define SHT_NOTE 7
+#define SHT_DYNSYM 11
+#define SHT_SUNW_cap 0x6ffffff5 /* SunOS 5.x hw/sw capabilities */
+
+/* elf type */
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+/* elf class */
+#define ELFCLASSNONE 0
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+/* magic number */
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_PAD 7
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+
+#define OLFMAG1 'O'
+#define OLFMAG "\177OLF"
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Addr p_paddr;
+ Elf64_Xword p_filesz;
+ Elf64_Xword p_memsz;
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+#define PT_NULL 0 /* p_type */
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_NUM 7
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Off sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Off sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Off sh_addralign;
+ Elf64_Off sh_entsize;
+} Elf64_Shdr;
+
+#define NT_NETBSD_CORE_PROCINFO 1
+#define NT_NETBSD_CORE_AUXV 2
+
+struct NetBSD_elfcore_procinfo {
+ /* Version 1 fields start here. */
+ uint32_t cpi_version; /* our version */
+ uint32_t cpi_cpisize; /* sizeof(this struct) */
+ uint32_t cpi_signo; /* killing signal */
+ uint32_t cpi_sigcode; /* signal code */
+ uint32_t cpi_sigpend[4]; /* pending signals */
+ uint32_t cpi_sigmask[4]; /* blocked signals */
+ uint32_t cpi_sigignore[4]; /* ignored signals */
+ uint32_t cpi_sigcatch[4]; /* caught signals */
+ int32_t cpi_pid; /* process ID */
+ int32_t cpi_ppid; /* parent process ID */
+ int32_t cpi_pgrp; /* process group ID */
+ int32_t cpi_sid; /* session ID */
+ uint32_t cpi_ruid; /* real user ID */
+ uint32_t cpi_euid; /* effective user ID */
+ uint32_t cpi_svuid; /* saved user ID */
+ uint32_t cpi_rgid; /* real group ID */
+ uint32_t cpi_egid; /* effective group ID */
+ uint32_t cpi_svgid; /* saved group ID */
+ uint32_t cpi_nlwps; /* number of LWPs */
+ int8_t cpi_name[32]; /* copy of p->p_comm */
+ /* Add version 2 fields below here. */
+ int32_t cpi_siglwp; /* LWP target of killing signal */
+};
+
+/* Note header in a PT_NOTE section */
+typedef struct elf_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+typedef struct {
+ Elf64_Word n_namesz;
+ Elf64_Word n_descsz;
+ Elf64_Word n_type;
+} Elf64_Nhdr;
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_PRXREG 4
+#define NT_TASKSTRUCT 4
+#define NT_PLATFORM 5
+#define NT_AUXV 6
+
+/* Note types used in executables */
+/* NetBSD executables (name = "NetBSD") */
+#define NT_NETBSD_VERSION 1
+#define NT_NETBSD_EMULATION 2
+#define NT_FREEBSD_VERSION 1
+#define NT_OPENBSD_VERSION 1
+#define NT_DRAGONFLY_VERSION 1
+/*
+ * GNU executables (name = "GNU")
+ * word[0]: GNU OS tags
+ * word[1]: major version
+ * word[2]: minor version
+ * word[3]: tiny version
+ */
+#define NT_GNU_VERSION 1
+
+/* GNU OS tags */
+#define GNU_OS_LINUX 0
+#define GNU_OS_HURD 1
+#define GNU_OS_SOLARIS 2
+#define GNU_OS_KFREEBSD 3
+#define GNU_OS_KNETBSD 4
+
+/*
+ * GNU Hardware capability information
+ * word[0]: Number of entries
+ * word[1]: Bitmask of enabled entries
+ * Followed by a byte id, and a NUL terminated string per entry
+ */
+#define NT_GNU_HWCAP 2
+
+/*
+ * GNU Build ID generated by ld
+ * 160 bit SHA1 [default]
+ * 128 bit md5 or uuid
+ */
+#define NT_GNU_BUILD_ID 3
+
+/*
+ * NetBSD-specific note type: PaX.
+ * There should be 1 NOTE per executable.
+ * name: PaX\0
+ * namesz: 4
+ * desc:
+ * word[0]: capability bitmask
+ * descsz: 4
+ */
+#define NT_NETBSD_PAX 3
+#define NT_NETBSD_PAX_MPROTECT 0x01 /* Force enable Mprotect */
+#define NT_NETBSD_PAX_NOMPROTECT 0x02 /* Force disable Mprotect */
+#define NT_NETBSD_PAX_GUARD 0x04 /* Force enable Segvguard */
+#define NT_NETBSD_PAX_NOGUARD 0x08 /* Force disable Servguard */
+#define NT_NETBSD_PAX_ASLR 0x10 /* Force enable ASLR */
+#define NT_NETBSD_PAX_NOASLR 0x20 /* Force disable ASLR */
+
+/*
+ * NetBSD-specific note type: MACHINE_ARCH.
+ * There should be 1 NOTE per executable.
+ * name: NetBSD\0
+ * namesz: 7
+ * desc: string
+ * descsz: variable
+ */
+#define NT_NETBSD_MARCH 5
+
+/*
+ * NetBSD-specific note type: COMPILER MODEL.
+ * There should be 1 NOTE per executable.
+ * name: NetBSD\0
+ * namesz: 7
+ * desc: string
+ * descsz: variable
+ */
+#define NT_NETBSD_CMODEL 6
+
+/*
+ * FreeBSD specific notes
+ */
+#define NT_FREEBSD_PROCSTAT_AUXV 16
+
+#if !defined(ELFSIZE) && defined(ARCH_ELFSIZE)
+#define ELFSIZE ARCH_ELFSIZE
+#endif
+/* SunOS 5.x hardware/software capabilities */
+typedef struct {
+ Elf32_Word c_tag;
+ union {
+ Elf32_Word c_val;
+ Elf32_Addr c_ptr;
+ } c_un;
+} Elf32_Cap;
+
+typedef struct {
+ Elf64_Xword c_tag;
+ union {
+ Elf64_Xword c_val;
+ Elf64_Addr c_ptr;
+ } c_un;
+} Elf64_Cap;
+
+/* SunOS 5.x hardware/software capability tags */
+#define CA_SUNW_NULL 0
+#define CA_SUNW_HW_1 1
+#define CA_SUNW_SF_1 2
+
+/* SunOS 5.x software capabilities */
+#define SF1_SUNW_FPKNWN 0x01
+#define SF1_SUNW_FPUSED 0x02
+#define SF1_SUNW_MASK 0x03
+
+/* SunOS 5.x hardware capabilities: sparc */
+#define AV_SPARC_MUL32 0x0001
+#define AV_SPARC_DIV32 0x0002
+#define AV_SPARC_FSMULD 0x0004
+#define AV_SPARC_V8PLUS 0x0008
+#define AV_SPARC_POPC 0x0010
+#define AV_SPARC_VIS 0x0020
+#define AV_SPARC_VIS2 0x0040
+#define AV_SPARC_ASI_BLK_INIT 0x0080
+#define AV_SPARC_FMAF 0x0100
+#define AV_SPARC_FJFMAU 0x4000
+#define AV_SPARC_IMA 0x8000
+
+/* SunOS 5.x hardware capabilities: 386 */
+#define AV_386_FPU 0x00000001
+#define AV_386_TSC 0x00000002
+#define AV_386_CX8 0x00000004
+#define AV_386_SEP 0x00000008
+#define AV_386_AMD_SYSC 0x00000010
+#define AV_386_CMOV 0x00000020
+#define AV_386_MMX 0x00000040
+#define AV_386_AMD_MMX 0x00000080
+#define AV_386_AMD_3DNow 0x00000100
+#define AV_386_AMD_3DNowx 0x00000200
+#define AV_386_FXSR 0x00000400
+#define AV_386_SSE 0x00000800
+#define AV_386_SSE2 0x00001000
+#define AV_386_PAUSE 0x00002000
+#define AV_386_SSE3 0x00004000
+#define AV_386_MON 0x00008000
+#define AV_386_CX16 0x00010000
+#define AV_386_AHF 0x00020000
+#define AV_386_TSCP 0x00040000
+#define AV_386_AMD_SSE4A 0x00080000
+#define AV_386_POPCNT 0x00100000
+#define AV_386_AMD_LZCNT 0x00200000
+#define AV_386_SSSE3 0x00400000
+#define AV_386_SSE4_1 0x00800000
+#define AV_386_SSE4_2 0x01000000
+
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/snprintf.c b/node_modules/mmmagic/deps/libmagic/src/snprintf.c
new file mode 100644
index 0000000..37e22c4
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/snprintf.c
@@ -0,0 +1,26 @@
+// XXX: added by mscdex
+// MSVS prior to version 2015 do not have a proper snprintf implementation
+#include <stdio.h>
+#include <stdarg.h>
+#if defined(_MSC_VER) && _MSC_VER < 1900
+ int vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
+ int count = -1;
+
+ if (size != 0)
+ count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
+ if (count == -1)
+ count = _vscprintf(format, ap);
+
+ return count;
+ }
+ int snprintf(char *outBuf, size_t size, const char *format, ...) {
+ int count;
+ va_list ap;
+
+ va_start(ap, format);
+ count = vsnprintf(outBuf, size, format, ap);
+ va_end(ap);
+
+ return count;
+ }
+#endif
diff --git a/node_modules/mmmagic/deps/libmagic/src/softmagic.c b/node_modules/mmmagic/deps/libmagic/src/softmagic.c
new file mode 100644
index 0000000..b9e9753
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/softmagic.c
@@ -0,0 +1,2076 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * softmagic - interpret variable magic from MAGIC
+ */
+
+#include "file.h"
+
+#ifndef lint
+FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $")
+#endif /* lint */
+
+#include "magic.h"
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <time.h>
+#include "der.h"
+
+private int match(struct magic_set *, struct magic *, uint32_t,
+ const unsigned char *, size_t, size_t, int, int, int, uint16_t *,
+ uint16_t *, int *, int *, int *);
+private int mget(struct magic_set *, const unsigned char *,
+ struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t *,
+ uint16_t *, int *, int *, int *);
+private int magiccheck(struct magic_set *, struct magic *);
+private int32_t mprint(struct magic_set *, struct magic *);
+private int moffset(struct magic_set *, struct magic *, size_t, int32_t *);
+private void mdebug(uint32_t, const char *, size_t);
+private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
+ const unsigned char *, uint32_t, size_t, struct magic *);
+private int mconvert(struct magic_set *, struct magic *, int);
+private int print_sep(struct magic_set *, int);
+private int handle_annotation(struct magic_set *, struct magic *, int);
+private int cvt_8(union VALUETYPE *, const struct magic *);
+private int cvt_16(union VALUETYPE *, const struct magic *);
+private int cvt_32(union VALUETYPE *, const struct magic *);
+private int cvt_64(union VALUETYPE *, const struct magic *);
+
+#define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o)))
+#define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
+ ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
+ ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
+ ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
+#define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
+ ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
+ ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
+ ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
+#define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
+ ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
+#define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
+ ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
+#define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
+ ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
+#define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
+#define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
+#define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
+
+/*
+ * softmagic - lookup one file in parsed, in-memory copy of database
+ * Passed the name and FILE * of one file to be typed.
+ */
+/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
+protected int
+file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
+ uint16_t *indir_count, uint16_t *name_count, int mode, int text)
+{
+ struct mlist *ml;
+ int rv, printed_something = 0, need_separator = 0;
+ uint16_t nc, ic;
+
+ if (name_count == NULL) {
+ nc = 0;
+ name_count = &nc;
+ }
+ if (indir_count == NULL) {
+ ic = 0;
+ indir_count = &ic;
+ }
+
+ for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
+ if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
+ text, 0, indir_count, name_count,
+ &printed_something, &need_separator, NULL)) != 0)
+ return rv;
+
+ return 0;
+}
+
+#define FILE_FMTDEBUG
+#ifdef FILE_FMTDEBUG
+#define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
+
+private const char * __attribute__((__format_arg__(3)))
+file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
+ const char *file, size_t line)
+{
+ const char *ptr = fmtcheck(m->desc, def);
+ if (ptr == def)
+ file_magerror(ms,
+ "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
+ " with `%s'", file, line, m->desc, def);
+ return ptr;
+}
+#else
+#define F(a, b, c) fmtcheck((b)->desc, (c))
+#endif
+
+/*
+ * Go through the whole list, stopping if you find a match. Process all
+ * the continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ * At any time when processing a successful top-level match, there is a
+ * current continuation level; it represents the level of the last
+ * successfully matched continuation.
+ *
+ * Continuations above that level are skipped as, if we see one, it
+ * means that the continuation that controls them - i.e, the
+ * lower-level continuation preceding them - failed to match.
+ *
+ * Continuations below that level are processed as, if we see one,
+ * it means we've finished processing or skipping higher-level
+ * continuations under the control of a successful or unsuccessful
+ * lower-level continuation, and are now seeing the next lower-level
+ * continuation and should process it. The current continuation
+ * level reverts to the level of the one we're seeing.
+ *
+ * Continuations at the current level are processed as, if we see
+ * one, there's no lower-level continuation that may have failed.
+ *
+ * If a continuation matches, we bump the current continuation level
+ * so that higher-level continuations are processed.
+ */
+private int
+match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
+ const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
+ int flip, uint16_t *indir_count, uint16_t *name_count,
+ int *printed_something, int *need_separator, int *returnval)
+{
+ uint32_t magindex = 0;
+ unsigned int cont_level = 0;
+ int returnvalv = 0, e; /* if a match is found it is set to 1*/
+ int firstline = 1; /* a flag to print X\n X\n- X */
+ int print = (ms->flags & MAGIC_NODESC) == 0;
+
+ if (returnval == NULL)
+ returnval = &returnvalv;
+
+ if (file_check_mem(ms, cont_level) == -1)
+ return -1;
+
+ for (magindex = 0; magindex < nmagic; magindex++) {
+ int flush = 0;
+ struct magic *m = &magic[magindex];
+
+ if (m->type != FILE_NAME)
+ if ((IS_STRING(m->type) &&
+#define FLT (STRING_BINTEST | STRING_TEXTTEST)
+ ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
+ (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
+ (m->flag & mode) != mode) {
+flush:
+ /* Skip sub-tests */
+ while (magindex < nmagic - 1 &&
+ magic[magindex + 1].cont_level != 0)
+ magindex++;
+ cont_level = 0;
+ continue; /* Skip to next top-level test*/
+ }
+
+ ms->offset = m->offset;
+ ms->line = m->lineno;
+
+ /* if main entry matches, print it... */
+ switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
+ flip, indir_count, name_count,
+ printed_something, need_separator, returnval)) {
+ case -1:
+ return -1;
+ case 0:
+ flush = m->reln != '!';
+ break;
+ default:
+ if (m->type == FILE_INDIRECT)
+ *returnval = 1;
+
+ switch (magiccheck(ms, m)) {
+ case -1:
+ return -1;
+ case 0:
+ flush++;
+ break;
+ default:
+ flush = 0;
+ break;
+ }
+ break;
+ }
+ if (flush) {
+ /*
+ * main entry didn't match,
+ * flush its continuations
+ */
+ goto flush;
+ }
+
+ if ((e = handle_annotation(ms, m, firstline)) != 0) {
+ *need_separator = 1;
+ *printed_something = 1;
+ *returnval = 1;
+ return e;
+ }
+
+ /*
+ * If we are going to print something, we'll need to print
+ * a blank before we print something else.
+ */
+ if (*m->desc) {
+ *need_separator = 1;
+ *printed_something = 1;
+ if (print_sep(ms, firstline) == -1)
+ return -1;
+ }
+
+
+ if (print && mprint(ms, m) == -1)
+ return -1;
+
+ switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) {
+ case -1:
+ case 0:
+ goto flush;
+ default:
+ break;
+ }
+
+ /* and any continuations that match */
+ if (file_check_mem(ms, ++cont_level) == -1)
+ return -1;
+
+ while (magindex + 1 < nmagic &&
+ magic[magindex + 1].cont_level != 0) {
+ m = &magic[++magindex];
+ ms->line = m->lineno; /* for messages */
+
+ if (cont_level < m->cont_level)
+ continue;
+ if (cont_level > m->cont_level) {
+ /*
+ * We're at the end of the level
+ * "cont_level" continuations.
+ */
+ cont_level = m->cont_level;
+ }
+ ms->offset = m->offset;
+ if (m->flag & OFFADD) {
+ ms->offset +=
+ ms->c.li[cont_level - 1].off;
+ }
+
+#ifdef ENABLE_CONDITIONALS
+ if (m->cond == COND_ELSE ||
+ m->cond == COND_ELIF) {
+ if (ms->c.li[cont_level].last_match == 1)
+ continue;
+ }
+#endif
+ switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
+ text, flip, indir_count, name_count,
+ printed_something, need_separator, returnval)) {
+ case -1:
+ return -1;
+ case 0:
+ if (m->reln != '!')
+ continue;
+ flush = 1;
+ break;
+ default:
+ if (m->type == FILE_INDIRECT)
+ *returnval = 1;
+ flush = 0;
+ break;
+ }
+
+ switch (flush ? 1 : magiccheck(ms, m)) {
+ case -1:
+ return -1;
+ case 0:
+#ifdef ENABLE_CONDITIONALS
+ ms->c.li[cont_level].last_match = 0;
+#endif
+ break;
+ default:
+#ifdef ENABLE_CONDITIONALS
+ ms->c.li[cont_level].last_match = 1;
+#endif
+ if (m->type == FILE_CLEAR)
+ ms->c.li[cont_level].got_match = 0;
+ else if (ms->c.li[cont_level].got_match) {
+ if (m->type == FILE_DEFAULT)
+ break;
+ } else
+ ms->c.li[cont_level].got_match = 1;
+
+ if ((e = handle_annotation(ms, m, firstline)) != 0) {
+ *need_separator = 1;
+ *printed_something = 1;
+ *returnval = 1;
+ return e;
+ }
+ /*
+ * If we are going to print something,
+ * make sure that we have a separator first.
+ */
+ if (*m->desc) {
+ if (!*printed_something) {
+ *printed_something = 1;
+ if (print_sep(ms, firstline)
+ == -1)
+ return -1;
+ }
+ }
+ /*
+ * This continuation matched. Print
+ * its message, with a blank before it
+ * if the previous item printed and
+ * this item isn't empty.
+ */
+ /* space if previous printed */
+ if (*need_separator
+ && ((m->flag & NOSPACE) == 0)
+ && *m->desc) {
+ if (print &&
+ file_printf(ms, " ") == -1)
+ return -1;
+ *need_separator = 0;
+ }
+ if (print && mprint(ms, m) == -1)
+ return -1;
+
+ switch (moffset(ms, m, nbytes,
+ &ms->c.li[cont_level].off)) {
+ case -1:
+ case 0:
+ flush = 1;
+ cont_level--;
+ break;
+ default:
+ break;
+ }
+
+ if (*m->desc)
+ *need_separator = 1;
+
+ /*
+ * If we see any continuations
+ * at a higher level,
+ * process them.
+ */
+ if (file_check_mem(ms, ++cont_level) == -1)
+ return -1;
+ break;
+ }
+ }
+ if (*printed_something) {
+ firstline = 0;
+ if (print)
+ *returnval = 1;
+ }
+ if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
+ return *returnval; /* don't keep searching */
+ }
+ cont_level = 0;
+ }
+ return *returnval; /* This is hit if -k is set or there is no match */
+}
+
+private int
+check_fmt(struct magic_set *ms, struct magic *m)
+{
+ file_regex_t rx;
+ int rc, rv = -1;
+
+ if (strchr(m->desc, '%') == NULL)
+ return 0;
+
+ rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
+ if (rc) {
+ file_regerror(&rx, rc, ms);
+ } else {
+ rc = file_regexec(&rx, m->desc, 0, 0, 0);
+ rv = !rc;
+ }
+ file_regfree(&rx);
+ return rv;
+}
+
+#ifndef HAVE_STRNDUP
+char * strndup(const char *, size_t);
+
+char *
+strndup(const char *str, size_t n)
+{
+ size_t len;
+ char *copy;
+
+ for (len = 0; len < n && str[len]; len++)
+ continue;
+ if ((copy = malloc(len + 1)) == NULL)
+ return NULL;
+ (void)memcpy(copy, str, len);
+ copy[len] = '\0';
+ return copy;
+}
+#endif /* HAVE_STRNDUP */
+
+private int32_t
+mprint(struct magic_set *ms, struct magic *m)
+{
+ uint64_t v;
+ float vf;
+ double vd;
+ int64_t t = 0;
+ char buf[128], tbuf[26], sbuf[512];
+ union VALUETYPE *p = &ms->ms_value;
+
+ switch (m->type) {
+ case FILE_BYTE:
+ v = file_signextend(ms, m, (uint64_t)p->b);
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%d",
+ (unsigned char)v);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%d"),
+ (unsigned char) v) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(char);
+ break;
+
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ v = file_signextend(ms, m, (uint64_t)p->h);
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%u",
+ (unsigned short)v);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%u"),
+ (unsigned short) v) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(short);
+ break;
+
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ v = file_signextend(ms, m, (uint64_t)p->l);
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(int32_t);
+ break;
+
+ case FILE_QUAD:
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ v = file_signextend(ms, m, p->q);
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
+ (unsigned long long)v);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
+ (unsigned long long) v) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(int64_t);
+ break;
+
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ if (m->reln == '=' || m->reln == '!') {
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), m->value.s))
+ == -1)
+ return -1;
+ t = ms->offset + m->vallen;
+ }
+ else {
+ char *str = p->s;
+
+ /* compute t before we mangle the string? */
+ t = ms->offset + strlen(str);
+
+ if (*m->value.s == '\0')
+ str[strcspn(str, "\r\n")] = '\0';
+
+ if (m->str_flags & STRING_TRIM) {
+ char *last;
+ while (isspace((unsigned char)*str))
+ str++;
+ last = str;
+ while (*last)
+ last++;
+ --last;
+ while (isspace((unsigned char)*last))
+ last--;
+ *++last = '\0';
+ }
+
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), str)) == -1)
+ return -1;
+
+ if (m->type == FILE_PSTRING)
+ t += file_pstring_length_size(m);
+ }
+ break;
+
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_fmttime(p->l, 0, tbuf)) == -1)
+ return -1;
+ t = ms->offset + sizeof(uint32_t);
+ break;
+
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
+ return -1;
+ t = ms->offset + sizeof(uint32_t);
+ break;
+
+ case FILE_QDATE:
+ case FILE_BEQDATE:
+ case FILE_LEQDATE:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_fmttime(p->q, 0, tbuf)) == -1)
+ return -1;
+ t = ms->offset + sizeof(uint64_t);
+ break;
+
+ case FILE_QLDATE:
+ case FILE_BEQLDATE:
+ case FILE_LEQLDATE:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
+ return -1;
+ t = ms->offset + sizeof(uint64_t);
+ break;
+
+ case FILE_QWDATE:
+ case FILE_BEQWDATE:
+ case FILE_LEQWDATE:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
+ return -1;
+ t = ms->offset + sizeof(uint64_t);
+ break;
+
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ vf = p->f;
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%g", vf);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(float);
+ break;
+
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ vd = p->d;
+ switch (check_fmt(ms, m)) {
+ case -1:
+ return -1;
+ case 1:
+ (void)snprintf(buf, sizeof(buf), "%g", vd);
+ if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
+ return -1;
+ break;
+ default:
+ if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
+ return -1;
+ break;
+ }
+ t = ms->offset + sizeof(double);
+ break;
+
+ case FILE_SEARCH:
+ case FILE_REGEX: {
+ char *cp;
+ int rval;
+
+ cp = strndup((const char *)ms->search.s, ms->search.rm_len);
+ if (cp == NULL) {
+ file_oomem(ms, ms->search.rm_len);
+ return -1;
+ }
+ rval = file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), cp));
+ free(cp);
+
+ if (rval == -1)
+ return -1;
+
+ if ((m->str_flags & REGEX_OFFSET_START))
+ t = ms->search.offset;
+ else
+ t = ms->search.offset + ms->search.rm_len;
+ break;
+ }
+
+ case FILE_DEFAULT:
+ case FILE_CLEAR:
+ if (file_printf(ms, "%s", m->desc) == -1)
+ return -1;
+ t = ms->offset;
+ break;
+
+ case FILE_INDIRECT:
+ case FILE_USE:
+ case FILE_NAME:
+ t = ms->offset;
+ break;
+ case FILE_DER:
+ if (file_printf(ms, F(ms, m, "%s"),
+ file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
+ return -1;
+ t = ms->offset;
+ break;
+ default:
+ file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
+ return -1;
+ }
+ return (int32_t)t;
+}
+
+private int
+moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op)
+{
+ int32_t o;
+
+ switch (m->type) {
+ case FILE_BYTE:
+ o = CAST(int32_t, (ms->offset + sizeof(char)));
+ break;
+
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ o = CAST(int32_t, (ms->offset + sizeof(short)));
+ break;
+
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
+ break;
+
+ case FILE_QUAD:
+ case FILE_BEQUAD:
+ case FILE_LEQUAD:
+ o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
+ break;
+
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ if (m->reln == '=' || m->reln == '!') {
+ o = ms->offset + m->vallen;
+ } else {
+ union VALUETYPE *p = &ms->ms_value;
+
+ if (*m->value.s == '\0')
+ p->s[strcspn(p->s, "\r\n")] = '\0';
+ o = CAST(uint32_t, (ms->offset + strlen(p->s)));
+ if (m->type == FILE_PSTRING)
+ o += (uint32_t)file_pstring_length_size(m);
+ }
+ break;
+
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
+ break;
+
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
+ break;
+
+ case FILE_QDATE:
+ case FILE_BEQDATE:
+ case FILE_LEQDATE:
+ o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
+ break;
+
+ case FILE_QLDATE:
+ case FILE_BEQLDATE:
+ case FILE_LEQLDATE:
+ o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
+ break;
+
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ o = CAST(int32_t, (ms->offset + sizeof(float)));
+ break;
+
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ o = CAST(int32_t, (ms->offset + sizeof(double)));
+ break;
+
+ case FILE_REGEX:
+ if ((m->str_flags & REGEX_OFFSET_START) != 0)
+ o = CAST(int32_t, ms->search.offset);
+ else
+ o = CAST(int32_t,
+ (ms->search.offset + ms->search.rm_len));
+ break;
+
+ case FILE_SEARCH:
+ if ((m->str_flags & REGEX_OFFSET_START) != 0)
+ o = CAST(int32_t, ms->search.offset);
+ else
+ o = CAST(int32_t, (ms->search.offset + m->vallen));
+ break;
+
+ case FILE_CLEAR:
+ case FILE_DEFAULT:
+ case FILE_INDIRECT:
+ o = ms->offset;
+ break;
+
+ case FILE_DER:
+ {
+ o = der_offs(ms, m, nbytes);
+ if (o == -1 || (size_t)o > nbytes) {
+ if ((ms->flags & MAGIC_DEBUG) != 0) {
+ (void)fprintf(stderr,
+ "Bad DER offset %d nbytes=%zu",
+ o, nbytes);
+ }
+ *op = 0;
+ return 0;
+ }
+ break;
+ }
+
+ default:
+ o = 0;
+ break;
+ }
+
+ if ((size_t)o > nbytes) {
+#if 0
+ file_error(ms, 0, "Offset out of range %zu > %zu",
+ (size_t)o, nbytes);
+#endif
+ return -1;
+ }
+ *op = o;
+ return 1;
+}
+
+private uint32_t
+cvt_id3(struct magic_set *ms, uint32_t v)
+{
+ v = ((((v >> 0) & 0x7f) << 0) |
+ (((v >> 8) & 0x7f) << 7) |
+ (((v >> 16) & 0x7f) << 14) |
+ (((v >> 24) & 0x7f) << 21));
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "id3 offs=%u\n", v);
+ return v;
+}
+
+private int
+cvt_flip(int type, int flip)
+{
+ if (flip == 0)
+ return type;
+ switch (type) {
+ case FILE_BESHORT:
+ return FILE_LESHORT;
+ case FILE_BELONG:
+ return FILE_LELONG;
+ case FILE_BEDATE:
+ return FILE_LEDATE;
+ case FILE_BELDATE:
+ return FILE_LELDATE;
+ case FILE_BEQUAD:
+ return FILE_LEQUAD;
+ case FILE_BEQDATE:
+ return FILE_LEQDATE;
+ case FILE_BEQLDATE:
+ return FILE_LEQLDATE;
+ case FILE_BEQWDATE:
+ return FILE_LEQWDATE;
+ case FILE_LESHORT:
+ return FILE_BESHORT;
+ case FILE_LELONG:
+ return FILE_BELONG;
+ case FILE_LEDATE:
+ return FILE_BEDATE;
+ case FILE_LELDATE:
+ return FILE_BELDATE;
+ case FILE_LEQUAD:
+ return FILE_BEQUAD;
+ case FILE_LEQDATE:
+ return FILE_BEQDATE;
+ case FILE_LEQLDATE:
+ return FILE_BEQLDATE;
+ case FILE_LEQWDATE:
+ return FILE_BEQWDATE;
+ case FILE_BEFLOAT:
+ return FILE_LEFLOAT;
+ case FILE_LEFLOAT:
+ return FILE_BEFLOAT;
+ case FILE_BEDOUBLE:
+ return FILE_LEDOUBLE;
+ case FILE_LEDOUBLE:
+ return FILE_BEDOUBLE;
+ default:
+ return type;
+ }
+}
+#define DO_CVT(fld, cast) \
+ if (m->num_mask) \
+ switch (m->mask_op & FILE_OPS_MASK) { \
+ case FILE_OPAND: \
+ p->fld &= cast m->num_mask; \
+ break; \
+ case FILE_OPOR: \
+ p->fld |= cast m->num_mask; \
+ break; \
+ case FILE_OPXOR: \
+ p->fld ^= cast m->num_mask; \
+ break; \
+ case FILE_OPADD: \
+ p->fld += cast m->num_mask; \
+ break; \
+ case FILE_OPMINUS: \
+ p->fld -= cast m->num_mask; \
+ break; \
+ case FILE_OPMULTIPLY: \
+ p->fld *= cast m->num_mask; \
+ break; \
+ case FILE_OPDIVIDE: \
+ if (cast m->num_mask == 0) \
+ return -1; \
+ p->fld /= cast m->num_mask; \
+ break; \
+ case FILE_OPMODULO: \
+ if (cast m->num_mask == 0) \
+ return -1; \
+ p->fld %= cast m->num_mask; \
+ break; \
+ } \
+ if (m->mask_op & FILE_OPINVERSE) \
+ p->fld = ~p->fld \
+
+private int
+cvt_8(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT(b, (uint8_t));
+ return 0;
+}
+
+private int
+cvt_16(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT(h, (uint16_t));
+ return 0;
+}
+
+private int
+cvt_32(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT(l, (uint32_t));
+ return 0;
+}
+
+private int
+cvt_64(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT(q, (uint64_t));
+ return 0;
+}
+
+#define DO_CVT2(fld, cast) \
+ if (m->num_mask) \
+ switch (m->mask_op & FILE_OPS_MASK) { \
+ case FILE_OPADD: \
+ p->fld += cast m->num_mask; \
+ break; \
+ case FILE_OPMINUS: \
+ p->fld -= cast m->num_mask; \
+ break; \
+ case FILE_OPMULTIPLY: \
+ p->fld *= cast m->num_mask; \
+ break; \
+ case FILE_OPDIVIDE: \
+ if (cast m->num_mask == 0) \
+ return -1; \
+ p->fld /= cast m->num_mask; \
+ break; \
+ } \
+
+private int
+cvt_float(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT2(f, (float));
+ return 0;
+}
+
+private int
+cvt_double(union VALUETYPE *p, const struct magic *m)
+{
+ DO_CVT2(d, (double));
+ return 0;
+}
+
+/*
+ * Convert the byte order of the data we are looking at
+ * While we're here, let's apply the mask operation
+ * (unless you have a better idea)
+ */
+private int
+mconvert(struct magic_set *ms, struct magic *m, int flip)
+{
+ union VALUETYPE *p = &ms->ms_value;
+
+ switch (cvt_flip(m->type, flip)) {
+ case FILE_BYTE:
+ if (cvt_8(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_SHORT:
+ if (cvt_16(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LONG:
+ case FILE_DATE:
+ case FILE_LDATE:
+ if (cvt_32(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_QUAD:
+ case FILE_QDATE:
+ case FILE_QLDATE:
+ case FILE_QWDATE:
+ if (cvt_64(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_STRING:
+ case FILE_BESTRING16:
+ case FILE_LESTRING16: {
+ /* Null terminate and eat *trailing* return */
+ p->s[sizeof(p->s) - 1] = '\0';
+ return 1;
+ }
+ case FILE_PSTRING: {
+ size_t sz = file_pstring_length_size(m);
+ char *ptr1 = p->s, *ptr2 = ptr1 + sz;
+ size_t len = file_pstring_get_length(m, ptr1);
+ sz = sizeof(p->s) - sz; /* maximum length of string */
+ if (len >= sz) {
+ /*
+ * The size of the pascal string length (sz)
+ * is 1, 2, or 4. We need at least 1 byte for NUL
+ * termination, but we've already truncated the
+ * string by p->s, so we need to deduct sz.
+ * Because we can use one of the bytes of the length
+ * after we shifted as NUL termination.
+ */
+ len = sz;
+ }
+ while (len--)
+ *ptr1++ = *ptr2++;
+ *ptr1 = '\0';
+ return 1;
+ }
+ case FILE_BESHORT:
+ p->h = (short)BE16(p);
+ if (cvt_16(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_BELONG:
+ case FILE_BEDATE:
+ case FILE_BELDATE:
+ p->l = (int32_t)BE32(p);
+ if (cvt_32(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_BEQUAD:
+ case FILE_BEQDATE:
+ case FILE_BEQLDATE:
+ case FILE_BEQWDATE:
+ p->q = (uint64_t)BE64(p);
+ if (cvt_64(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LESHORT:
+ p->h = (short)LE16(p);
+ if (cvt_16(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LELONG:
+ case FILE_LEDATE:
+ case FILE_LELDATE:
+ p->l = (int32_t)LE32(p);
+ if (cvt_32(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LEQUAD:
+ case FILE_LEQDATE:
+ case FILE_LEQLDATE:
+ case FILE_LEQWDATE:
+ p->q = (uint64_t)LE64(p);
+ if (cvt_64(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_MELONG:
+ case FILE_MEDATE:
+ case FILE_MELDATE:
+ p->l = (int32_t)ME32(p);
+ if (cvt_32(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_FLOAT:
+ if (cvt_float(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_BEFLOAT:
+ p->l = BE32(p);
+ if (cvt_float(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LEFLOAT:
+ p->l = LE32(p);
+ if (cvt_float(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_DOUBLE:
+ if (cvt_double(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_BEDOUBLE:
+ p->q = BE64(p);
+ if (cvt_double(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_LEDOUBLE:
+ p->q = LE64(p);
+ if (cvt_double(p, m) == -1)
+ goto out;
+ return 1;
+ case FILE_REGEX:
+ case FILE_SEARCH:
+ case FILE_DEFAULT:
+ case FILE_CLEAR:
+ case FILE_NAME:
+ case FILE_USE:
+ case FILE_DER:
+ return 1;
+ default:
+ file_magerror(ms, "invalid type %d in mconvert()", m->type);
+ return 0;
+ }
+out:
+ file_magerror(ms, "zerodivide in mconvert()");
+ return 0;
+}
+
+
+private void
+mdebug(uint32_t offset, const char *str, size_t len)
+{
+ (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
+ file_showstr(stderr, str, len);
+ (void) fputc('\n', stderr);
+ (void) fputc('\n', stderr);
+}
+
+private int
+mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
+ const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
+{
+ /*
+ * Note: FILE_SEARCH and FILE_REGEX do not actually copy
+ * anything, but setup pointers into the source
+ */
+ if (indir == 0) {
+ switch (type) {
+ case FILE_DER:
+ case FILE_SEARCH:
+ if (offset > nbytes)
+ offset = CAST(uint32_t, nbytes);
+ ms->search.s = RCAST(const char *, s) + offset;
+ ms->search.s_len = nbytes - offset;
+ ms->search.offset = offset;
+ return 0;
+
+ case FILE_REGEX: {
+ const char *b;
+ const char *c;
+ const char *last; /* end of search region */
+ const char *buf; /* start of search region */
+ const char *end;
+ size_t lines, linecnt, bytecnt;
+
+ if (s == NULL || nbytes < offset) {
+ ms->search.s_len = 0;
+ ms->search.s = NULL;
+ return 0;
+ }
+
+ if (m->str_flags & REGEX_LINE_COUNT) {
+ linecnt = m->str_range;
+ bytecnt = linecnt * 80;
+ } else {
+ linecnt = 0;
+ bytecnt = m->str_range;
+ }
+
+ if (bytecnt == 0 || bytecnt > nbytes - offset)
+ bytecnt = nbytes - offset;
+ if (bytecnt > ms->regex_max)
+ bytecnt = ms->regex_max;
+
+ buf = RCAST(const char *, s) + offset;
+ end = last = RCAST(const char *, s) + bytecnt + offset;
+ /* mget() guarantees buf <= last */
+ for (lines = linecnt, b = buf; lines && b < end &&
+ ((b = CAST(const char *,
+ memchr(c = b, '\n', CAST(size_t, (end - b)))))
+ || (b = CAST(const char *,
+ memchr(c, '\r', CAST(size_t, (end - c))))));
+ lines--, b++) {
+ last = b;
+ if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
+ b++;
+ }
+ if (lines)
+ last = RCAST(const char *, s) + bytecnt;
+
+ ms->search.s = buf;
+ ms->search.s_len = last - buf;
+ ms->search.offset = offset;
+ ms->search.rm_len = 0;
+ return 0;
+ }
+ case FILE_BESTRING16:
+ case FILE_LESTRING16: {
+ const unsigned char *src = s + offset;
+ const unsigned char *esrc = s + nbytes;
+ char *dst = p->s;
+ char *edst = &p->s[sizeof(p->s) - 1];
+
+ if (type == FILE_BESTRING16)
+ src++;
+
+ /* check that offset is within range */
+ if (offset >= nbytes)
+ break;
+ for (/*EMPTY*/; src < esrc; src += 2, dst++) {
+ if (dst < edst)
+ *dst = *src;
+ else
+ break;
+ if (*dst == '\0') {
+ if (type == FILE_BESTRING16 ?
+ *(src - 1) != '\0' :
+ ((src + 1 < esrc) &&
+ *(src + 1) != '\0'))
+ *dst = ' ';
+ }
+ }
+ *edst = '\0';
+ return 0;
+ }
+ case FILE_STRING: /* XXX - these two should not need */
+ case FILE_PSTRING: /* to copy anything, but do anyway. */
+ default:
+ break;
+ }
+ }
+
+ if (offset >= nbytes) {
+ (void)memset(p, '\0', sizeof(*p));
+ return 0;
+ }
+ if (nbytes - offset < sizeof(*p))
+ nbytes = nbytes - offset;
+ else
+ nbytes = sizeof(*p);
+
+ (void)memcpy(p, s + offset, nbytes);
+
+ /*
+ * the usefulness of padding with zeroes eludes me, it
+ * might even cause problems
+ */
+ if (nbytes < sizeof(*p))
+ (void)memset(((char *)(void *)p) + nbytes, '\0',
+ sizeof(*p) - nbytes);
+ return 0;
+}
+
+private uint32_t
+do_ops(struct magic *m, intmax_t lhs, intmax_t off)
+{
+ intmax_t offset;
+ if (off) {
+ switch (m->in_op & FILE_OPS_MASK) {
+ case FILE_OPAND:
+ offset = lhs & off;
+ break;
+ case FILE_OPOR:
+ offset = lhs | off;
+ break;
+ case FILE_OPXOR:
+ offset = lhs ^ off;
+ break;
+ case FILE_OPADD:
+ offset = lhs + off;
+ break;
+ case FILE_OPMINUS:
+ offset = lhs - off;
+ break;
+ case FILE_OPMULTIPLY:
+ offset = lhs * off;
+ break;
+ case FILE_OPDIVIDE:
+ offset = lhs / off;
+ break;
+ case FILE_OPMODULO:
+ offset = lhs % off;
+ break;
+ }
+ } else
+ offset = lhs;
+ if (m->in_op & FILE_OPINVERSE)
+ offset = ~offset;
+
+ return (uint32_t)offset;
+}
+
+private int
+mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
+ size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
+ int flip, uint16_t *indir_count, uint16_t *name_count,
+ int *printed_something, int *need_separator, int *returnval)
+{
+ uint32_t offset = ms->offset;
+ intmax_t lhs;
+ file_pushbuf_t *pb;
+ int rv, oneed_separator, in_type;
+ char *rbuf;
+ union VALUETYPE *p = &ms->ms_value;
+ struct mlist ml;
+
+ if (*indir_count >= ms->indir_max) {
+ file_error(ms, 0, "indirect count (%hu) exceeded",
+ *indir_count);
+ return -1;
+ }
+
+ if (*name_count >= ms->name_max) {
+ file_error(ms, 0, "name use count (%hu) exceeded",
+ *name_count);
+ return -1;
+ }
+
+ if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
+ (uint32_t)nbytes, m) == -1)
+ return -1;
+
+ if ((ms->flags & MAGIC_DEBUG) != 0) {
+ fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
+ SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
+ "u, il=%hu, nc=%hu)\n",
+ m->type, m->flag, offset, o, nbytes,
+ *indir_count, *name_count);
+ mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
+#ifndef COMPILE_ONLY
+ file_mdump(m);
+#endif
+ }
+
+ if (m->flag & INDIR) {
+ intmax_t off = m->in_offset;
+ const int sgn = m->in_op & FILE_OPSIGNED;
+ if (m->in_op & FILE_OPINDIRECT) {
+ const union VALUETYPE *q = CAST(const union VALUETYPE *,
+ ((const void *)(s + offset + off)));
+ if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
+ return 0;
+ switch (cvt_flip(m->in_type, flip)) {
+ case FILE_BYTE:
+ off = SEXT(sgn,8,q->b);
+ break;
+ case FILE_SHORT:
+ off = SEXT(sgn,16,q->h);
+ break;
+ case FILE_BESHORT:
+ off = SEXT(sgn,16,BE16(q));
+ break;
+ case FILE_LESHORT:
+ off = SEXT(sgn,16,LE16(q));
+ break;
+ case FILE_LONG:
+ off = SEXT(sgn,32,q->l);
+ break;
+ case FILE_BELONG:
+ case FILE_BEID3:
+ off = SEXT(sgn,32,BE32(q));
+ break;
+ case FILE_LEID3:
+ case FILE_LELONG:
+ off = SEXT(sgn,32,LE32(q));
+ break;
+ case FILE_MELONG:
+ off = SEXT(sgn,32,ME32(q));
+ break;
+ }
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "indirect offs=%jd\n", off);
+ }
+ switch (in_type = cvt_flip(m->in_type, flip)) {
+ case FILE_BYTE:
+ if (OFFSET_OOB(nbytes, offset, 1))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,8,p->b), off);
+ break;
+ case FILE_BESHORT:
+ if (OFFSET_OOB(nbytes, offset, 2))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
+ break;
+ case FILE_LESHORT:
+ if (OFFSET_OOB(nbytes, offset, 2))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
+ break;
+ case FILE_SHORT:
+ if (OFFSET_OOB(nbytes, offset, 2))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,16,p->h), off);
+ break;
+ case FILE_BELONG:
+ case FILE_BEID3:
+ if (OFFSET_OOB(nbytes, offset, 4))
+ return 0;
+ lhs = BE32(p);
+ if (in_type == FILE_BEID3)
+ lhs = cvt_id3(ms, (uint32_t)lhs);
+ offset = do_ops(m, SEXT(sgn,32,lhs), off);
+ break;
+ case FILE_LELONG:
+ case FILE_LEID3:
+ if (OFFSET_OOB(nbytes, offset, 4))
+ return 0;
+ lhs = LE32(p);
+ if (in_type == FILE_LEID3)
+ lhs = cvt_id3(ms, (uint32_t)lhs);
+ offset = do_ops(m, SEXT(sgn,32,lhs), off);
+ break;
+ case FILE_MELONG:
+ if (OFFSET_OOB(nbytes, offset, 4))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
+ break;
+ case FILE_LONG:
+ if (OFFSET_OOB(nbytes, offset, 4))
+ return 0;
+ offset = do_ops(m, SEXT(sgn,32,p->l), off);
+ break;
+ default:
+ break;
+ }
+
+ if (m->flag & INDIROFFADD) {
+ offset += ms->c.li[cont_level-1].off;
+ if (offset == 0) {
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr,
+ "indirect *zero* offset\n");
+ return 0;
+ }
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "indirect +offs=%u\n", offset);
+ }
+ if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
+ return -1;
+ ms->offset = offset;
+
+ if ((ms->flags & MAGIC_DEBUG) != 0) {
+ mdebug(offset, (char *)(void *)p,
+ sizeof(union VALUETYPE));
+#ifndef COMPILE_ONLY
+ file_mdump(m);
+#endif
+ }
+ }
+
+ /* Verify we have enough data to match magic type */
+ switch (m->type) {
+ case FILE_BYTE:
+ if (OFFSET_OOB(nbytes, offset, 1))
+ return 0;
+ break;
+
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ if (OFFSET_OOB(nbytes, offset, 2))
+ return 0;
+ break;
+
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ if (OFFSET_OOB(nbytes, offset, 4))
+ return 0;
+ break;
+
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ if (OFFSET_OOB(nbytes, offset, 8))
+ return 0;
+ break;
+
+ case FILE_STRING:
+ case FILE_PSTRING:
+ case FILE_SEARCH:
+ if (OFFSET_OOB(nbytes, offset, m->vallen))
+ return 0;
+ break;
+
+ case FILE_REGEX:
+ if (nbytes < offset)
+ return 0;
+ break;
+
+ case FILE_INDIRECT:
+ if (m->str_flags & INDIRECT_RELATIVE)
+ offset += CAST(uint32_t, o);
+ if (offset == 0)
+ return 0;
+
+ if (nbytes < offset)
+ return 0;
+
+ if ((pb = file_push_buffer(ms)) == NULL)
+ return -1;
+
+ (*indir_count)++;
+ rv = file_softmagic(ms, s + offset, nbytes - offset,
+ indir_count, name_count, BINTEST, text);
+
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
+
+ rbuf = file_pop_buffer(ms, pb);
+ if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
+ return -1;
+
+ if (rv == 1) {
+ if ((ms->flags & MAGIC_NODESC) == 0 &&
+ file_printf(ms, F(ms, m, "%u"), offset) == -1) {
+ free(rbuf);
+ return -1;
+ }
+ if (file_printf(ms, "%s", rbuf) == -1) {
+ free(rbuf);
+ return -1;
+ }
+ }
+ free(rbuf);
+ return rv;
+
+ case FILE_USE:
+ if (nbytes < offset)
+ return 0;
+ rbuf = m->value.s;
+ if (*rbuf == '^') {
+ rbuf++;
+ flip = !flip;
+ }
+ if (file_magicfind(ms, rbuf, &ml) == -1) {
+ file_error(ms, 0, "cannot find entry `%s'", rbuf);
+ return -1;
+ }
+ (*name_count)++;
+ oneed_separator = *need_separator;
+ if (m->flag & NOSPACE)
+ *need_separator = 0;
+ rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
+ mode, text, flip, indir_count, name_count,
+ printed_something, need_separator, returnval);
+ if (rv != 1)
+ *need_separator = oneed_separator;
+ return 1;
+
+ case FILE_NAME:
+ if (ms->flags & MAGIC_NODESC)
+ return 1;
+ if (file_printf(ms, "%s", m->desc) == -1)
+ return -1;
+ return 1;
+ case FILE_DER:
+ case FILE_DEFAULT: /* nothing to check */
+ case FILE_CLEAR:
+ default:
+ break;
+ }
+ if (!mconvert(ms, m, flip))
+ return 0;
+ return 1;
+}
+
+private uint64_t
+file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
+{
+ /*
+ * Convert the source args to unsigned here so that (1) the
+ * compare will be unsigned as it is in strncmp() and (2) so
+ * the ctype functions will work correctly without extra
+ * casting.
+ */
+ const unsigned char *a = (const unsigned char *)s1;
+ const unsigned char *b = (const unsigned char *)s2;
+ const unsigned char *eb = b + len;
+ uint64_t v;
+
+ /*
+ * What we want here is v = strncmp(s1, s2, len),
+ * but ignoring any nulls.
+ */
+ v = 0;
+ if (0L == flags) { /* normal string: do it fast */
+ while (len-- > 0)
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
+ else { /* combine the others */
+ while (len-- > 0) {
+ if (b >= eb) {
+ v = 1;
+ break;
+ }
+ if ((flags & STRING_IGNORE_LOWERCASE) &&
+ islower(*a)) {
+ if ((v = tolower(*b++) - *a++) != '\0')
+ break;
+ }
+ else if ((flags & STRING_IGNORE_UPPERCASE) &&
+ isupper(*a)) {
+ if ((v = toupper(*b++) - *a++) != '\0')
+ break;
+ }
+ else if ((flags & STRING_COMPACT_WHITESPACE) &&
+ isspace(*a)) {
+ a++;
+ if (isspace(*b++)) {
+ if (!isspace(*a))
+ while (b < eb && isspace(*b))
+ b++;
+ }
+ else {
+ v = 1;
+ break;
+ }
+ }
+ else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
+ isspace(*a)) {
+ a++;
+ while (b < eb && isspace(*b))
+ b++;
+ }
+ else {
+ if ((v = *b++ - *a++) != '\0')
+ break;
+ }
+ }
+ }
+ return v;
+}
+
+private uint64_t
+file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
+{
+ /*
+ * XXX - The 16-bit string compare probably needs to be done
+ * differently, especially if the flags are to be supported.
+ * At the moment, I am unsure.
+ */
+ flags = 0;
+ return file_strncmp(a, b, len, flags);
+}
+
+private int
+magiccheck(struct magic_set *ms, struct magic *m)
+{
+ uint64_t l = m->value.q;
+ uint64_t v;
+ float fl, fv;
+ double dl, dv;
+ int matched;
+ union VALUETYPE *p = &ms->ms_value;
+
+ switch (m->type) {
+ case FILE_BYTE:
+ v = p->b;
+ break;
+
+ case FILE_SHORT:
+ case FILE_BESHORT:
+ case FILE_LESHORT:
+ v = p->h;
+ break;
+
+ case FILE_LONG:
+ case FILE_BELONG:
+ case FILE_LELONG:
+ case FILE_MELONG:
+ case FILE_DATE:
+ case FILE_BEDATE:
+ case FILE_LEDATE:
+ case FILE_MEDATE:
+ case FILE_LDATE:
+ case FILE_BELDATE:
+ case FILE_LELDATE:
+ case FILE_MELDATE:
+ v = p->l;
+ break;
+
+ case FILE_QUAD:
+ case FILE_LEQUAD:
+ case FILE_BEQUAD:
+ case FILE_QDATE:
+ case FILE_BEQDATE:
+ case FILE_LEQDATE:
+ case FILE_QLDATE:
+ case FILE_BEQLDATE:
+ case FILE_LEQLDATE:
+ case FILE_QWDATE:
+ case FILE_BEQWDATE:
+ case FILE_LEQWDATE:
+ v = p->q;
+ break;
+
+ case FILE_FLOAT:
+ case FILE_BEFLOAT:
+ case FILE_LEFLOAT:
+ fl = m->value.f;
+ fv = p->f;
+ switch (m->reln) {
+ case 'x':
+ matched = 1;
+ break;
+
+ case '!':
+ matched = fv != fl;
+ break;
+
+ case '=':
+ matched = fv == fl;
+ break;
+
+ case '>':
+ matched = fv > fl;
+ break;
+
+ case '<':
+ matched = fv < fl;
+ break;
+
+ default:
+ file_magerror(ms, "cannot happen with float: invalid relation `%c'",
+ m->reln);
+ return -1;
+ }
+ return matched;
+
+ case FILE_DOUBLE:
+ case FILE_BEDOUBLE:
+ case FILE_LEDOUBLE:
+ dl = m->value.d;
+ dv = p->d;
+ switch (m->reln) {
+ case 'x':
+ matched = 1;
+ break;
+
+ case '!':
+ matched = dv != dl;
+ break;
+
+ case '=':
+ matched = dv == dl;
+ break;
+
+ case '>':
+ matched = dv > dl;
+ break;
+
+ case '<':
+ matched = dv < dl;
+ break;
+
+ default:
+ file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
+ return -1;
+ }
+ return matched;
+
+ case FILE_DEFAULT:
+ case FILE_CLEAR:
+ l = 0;
+ v = 0;
+ break;
+
+ case FILE_STRING:
+ case FILE_PSTRING:
+ l = 0;
+ v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
+ break;
+
+ case FILE_BESTRING16:
+ case FILE_LESTRING16:
+ l = 0;
+ v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
+ break;
+
+ case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
+ size_t slen;
+ size_t idx;
+
+ if (ms->search.s == NULL)
+ return 0;
+
+ slen = MIN(m->vallen, sizeof(m->value.s));
+ l = 0;
+ v = 0;
+
+ for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
+ if (slen + idx > ms->search.s_len)
+ return 0;
+
+ v = file_strncmp(m->value.s, ms->search.s + idx, slen,
+ m->str_flags);
+ if (v == 0) { /* found match */
+ ms->search.offset += idx;
+ ms->search.rm_len = ms->search.s_len - idx;
+ break;
+ }
+ }
+ break;
+ }
+ case FILE_REGEX: {
+ int rc;
+ file_regex_t rx;
+ const char *search;
+
+ if (ms->search.s == NULL)
+ return 0;
+
+ l = 0;
+ rc = file_regcomp(&rx, m->value.s,
+ REG_EXTENDED|REG_NEWLINE|
+ ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
+ if (rc) {
+ file_regerror(&rx, rc, ms);
+ v = (uint64_t)-1;
+ } else {
+ regmatch_t pmatch;
+ size_t slen = ms->search.s_len;
+ char *copy;
+ if (slen != 0) {
+ copy = CAST(char *, malloc(slen));
+ if (copy == NULL) {
+ file_regfree(&rx);
+ file_error(ms, errno,
+ "can't allocate %" SIZE_T_FORMAT "u bytes",
+ slen);
+ return -1;
+ }
+ memcpy(copy, ms->search.s, slen);
+ copy[--slen] = '\0';
+ search = copy;
+ } else {
+ search = CCAST(char *, "");
+ copy = NULL;
+ }
+ rc = file_regexec(&rx, (const char *)search,
+ 1, &pmatch, 0);
+ free(copy);
+ switch (rc) {
+ case 0:
+ ms->search.s += (int)pmatch.rm_so;
+ ms->search.offset += (size_t)pmatch.rm_so;
+ ms->search.rm_len =
+ (size_t)(pmatch.rm_eo - pmatch.rm_so);
+ v = 0;
+ break;
+
+ case REG_NOMATCH:
+ v = 1;
+ break;
+
+ default:
+ file_regerror(&rx, rc, ms);
+ v = (uint64_t)-1;
+ break;
+ }
+ }
+ file_regfree(&rx);
+ if (v == (uint64_t)-1)
+ return -1;
+ break;
+ }
+ case FILE_INDIRECT:
+ case FILE_USE:
+ case FILE_NAME:
+ return 1;
+ case FILE_DER:
+ matched = der_cmp(ms, m);
+ if (matched == -1) {
+ if ((ms->flags & MAGIC_DEBUG) != 0) {
+ (void) fprintf(stderr,
+ "EOF comparing DER entries");
+ }
+ return 0;
+ }
+ return matched;
+ default:
+ file_magerror(ms, "invalid type %d in magiccheck()", m->type);
+ return -1;
+ }
+
+ v = file_signextend(ms, m, v);
+
+ switch (m->reln) {
+ case 'x':
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT
+ "u == *any* = 1\n", (unsigned long long)v);
+ matched = 1;
+ break;
+
+ case '!':
+ matched = v != l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
+ INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
+ (unsigned long long)l, matched);
+ break;
+
+ case '=':
+ matched = v == l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
+ INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
+ (unsigned long long)l, matched);
+ break;
+
+ case '>':
+ if (m->flag & UNSIGNED) {
+ matched = v > l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT
+ "u > %" INT64_T_FORMAT "u = %d\n",
+ (unsigned long long)v,
+ (unsigned long long)l, matched);
+ }
+ else {
+ matched = (int64_t) v > (int64_t) l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT
+ "d > %" INT64_T_FORMAT "d = %d\n",
+ (long long)v, (long long)l, matched);
+ }
+ break;
+
+ case '<':
+ if (m->flag & UNSIGNED) {
+ matched = v < l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT
+ "u < %" INT64_T_FORMAT "u = %d\n",
+ (unsigned long long)v,
+ (unsigned long long)l, matched);
+ }
+ else {
+ matched = (int64_t) v < (int64_t) l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "%" INT64_T_FORMAT
+ "d < %" INT64_T_FORMAT "d = %d\n",
+ (long long)v, (long long)l, matched);
+ }
+ break;
+
+ case '&':
+ matched = (v & l) == l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
+ INT64_T_FORMAT "x) == %" INT64_T_FORMAT
+ "x) = %d\n", (unsigned long long)v,
+ (unsigned long long)l, (unsigned long long)l,
+ matched);
+ break;
+
+ case '^':
+ matched = (v & l) != l;
+ if ((ms->flags & MAGIC_DEBUG) != 0)
+ (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
+ INT64_T_FORMAT "x) != %" INT64_T_FORMAT
+ "x) = %d\n", (unsigned long long)v,
+ (unsigned long long)l, (unsigned long long)l,
+ matched);
+ break;
+
+ default:
+ file_magerror(ms, "cannot happen: invalid relation `%c'",
+ m->reln);
+ return -1;
+ }
+
+ return matched;
+}
+
+private int
+handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
+{
+ if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
+ if (!firstline && file_printf(ms, "\n- ") == -1)
+ return -1;
+ if (file_printf(ms, "%.8s", m->apple) == -1)
+ return -1;
+ return 1;
+ }
+ if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
+ if (!firstline && file_printf(ms, "\n- ") == -1)
+ return -1;
+ if (file_printf(ms, "%s", m->ext) == -1)
+ return -1;
+ return 1;
+ }
+ if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
+ if (!firstline && file_printf(ms, "\n- ") == -1)
+ return -1;
+ if (file_printf(ms, "%s", m->mimetype) == -1)
+ return -1;
+ return 1;
+ }
+ return 0;
+}
+
+private int
+print_sep(struct magic_set *ms, int firstline)
+{
+// if (ms->flags & MAGIC_NODESC)
+// return 0;
+ if (firstline)
+ return 0;
+ /*
+ * we found another match
+ * put a newline and '-' to do some simple formatting
+ */
+ return file_printf(ms, "\n- ");
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/strcasestr.c b/node_modules/mmmagic/deps/libmagic/src/strcasestr.c
new file mode 100644
index 0000000..3db407f
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/strcasestr.c
@@ -0,0 +1,84 @@
+/* $NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: strcasestr.c,v 1.3 2005/11/29 03:12:00 christos Exp $");
+__RCSID("$NetBSD: strncasecmp.c,v 1.2 2007/06/04 18:19:27 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "file.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+static int
+_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ if (n != 0) {
+ const unsigned char *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ do {
+ if (tolower(*us1) != tolower(*us2++))
+ return tolower(*us1) - tolower(*--us2);
+ if (*us1++ == '\0')
+ break;
+ } while (--n != 0);
+ }
+ return 0;
+}
+
+/*
+ * Find the first occurrence of find in s, ignore case.
+ */
+char *
+strcasestr(const char *s, const char *find)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != 0) {
+ c = tolower((unsigned char)c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ } while ((char)tolower((unsigned char)sc) != c);
+ } while (_strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return (char *)(intptr_t)(s);
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/strlcat.c b/node_modules/mmmagic/deps/libmagic/src/strlcat.c
new file mode 100644
index 0000000..9692bc1
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/strlcat.c
@@ -0,0 +1,58 @@
+/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */
+#include "file.h"
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left). At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+ size_t dlen;
+
+ /* Find the end of dst and adjust bytes left but don't go past end */
+ while (n-- != 0 && *d != '\0')
+ d++;
+ dlen = d - dst;
+ n = siz - dlen;
+
+ if (n == 0)
+ return(dlen + strlen(s));
+ while (*s != '\0') {
+ if (n != 1) {
+ *d++ = *s;
+ n--;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return(dlen + (s - src)); /* count does not include NUL */
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/strlcpy.c b/node_modules/mmmagic/deps/libmagic/src/strlcpy.c
new file mode 100644
index 0000000..992501c
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/strlcpy.c
@@ -0,0 +1,54 @@
+/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */
+#include "file.h"
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+ char *d = dst;
+ const char *s = src;
+ size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/node_modules/mmmagic/deps/libmagic/src/tar.h b/node_modules/mmmagic/deps/libmagic/src/tar.h
new file mode 100644
index 0000000..854d455
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/tar.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) Ian F. Darwin 1986-1995.
+ * Software written by Ian F. Darwin and others;
+ * maintained 1995-present by Christos Zoulas and others.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Header file for public domain tar (tape archive) program.
+ *
+ * @(#)tar.h 1.20 86/10/29 Public Domain.
+ *
+ * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu.
+ *
+ * $File: tar.h,v 1.13 2010/11/30 14:58:53 rrt Exp $ # checkin only
+ */
+
+/*
+ * Header block on tape.
+ *
+ * I'm going to use traditional DP naming conventions here.
+ * A "block" is a big chunk of stuff that we do I/O on.
+ * A "record" is a piece of info that we care about.
+ * Typically many "record"s fit into a "block".
+ */
+#define RECORDSIZE 512
+#define NAMSIZ 100
+#define TUNMLEN 32
+#define TGNMLEN 32
+
+union record {
+ unsigned char charptr[RECORDSIZE];
+ struct header {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ char magic[8];
+ char uname[TUNMLEN];
+ char gname[TGNMLEN];
+ char devmajor[8];
+ char devminor[8];
+ } header;
+};
+
+/* The magic field is filled with this if uname and gname are valid. */
+#define TMAGIC "ustar" /* 5 chars and a null */
+#define GNUTMAGIC "ustar " /* 7 chars and a null */
diff --git a/node_modules/mmmagic/deps/libmagic/src/vasprintf.c b/node_modules/mmmagic/deps/libmagic/src/vasprintf.c
new file mode 100644
index 0000000..9548fd8
--- /dev/null
+++ b/node_modules/mmmagic/deps/libmagic/src/vasprintf.c
@@ -0,0 +1,27 @@
+// XXX: change by mscdex
+// from mingw-w64-crt project
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int vasprintf(char ** ret, const char * format, va_list ap) {
+ int len;
+ /* Get Length */
+ len = _vsnprintf(NULL, 0, format, ap);
+ if (len < 0)
+ return -1;
+ /* +1 for \0 terminator. */
+ *ret = malloc(len + 1);
+ /* Check malloc fail*/
+ if (!*ret) {
+ errno = ENOMEM;
+ return -1;
+ }
+ /* Write String */
+ _vsnprintf(*ret, len + 1, format, ap);
+ /* Terminate explicitly */
+ (*ret)[len] = '\0';
+ return len;
+}