diff options
Diffstat (limited to 'node_modules/mmmagic/deps')
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 (®exp, 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 (®exp); + 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 (®exp, 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 (®exp); + + 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 (¤t_token, regexp, syntax | RE_CARET_ANCHORS_HERE); + tree = parse_reg_exp (regexp, preg, ¤t_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, ¬ecount) == -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, ¬ecount) == -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, ¬ecount) == -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 = §ioninfo[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 = ⁣ + } + + 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; +} |