Annotation of embedaddon/php/ext/fileinfo/libmagic/apprentice.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) Ian F. Darwin 1986-1995.
        !             3:  * Software written by Ian F. Darwin and others;
        !             4:  * maintained 1995-present by Christos Zoulas and others.
        !             5:  * 
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice immediately at the beginning of the file, without modification,
        !            11:  *    this list of conditions, and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *  
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            20:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            26:  * SUCH DAMAGE.
        !            27:  */
        !            28: /*
        !            29:  * apprentice - make one pass through /etc/magic, learning its secrets.
        !            30:  */
        !            31: 
        !            32: #include "php.h"
        !            33: 
        !            34: #include "file.h"
        !            35: 
        !            36: #ifndef        lint
        !            37: FILE_RCSID("@(#)$File: apprentice.c,v 1.151 2009/03/18 15:19:23 christos Exp $")
        !            38: #endif /* lint */
        !            39: 
        !            40: #include "magic.h"
        !            41: #include "patchlevel.h"
        !            42: #include <stdlib.h>
        !            43: 
        !            44: #if defined(__hpux) && !defined(HAVE_STRTOULL)
        !            45: #if SIZEOF_LONG == 8
        !            46: # define strtoull strtoul
        !            47: #else
        !            48: # define strtoull __strtoull
        !            49: #endif
        !            50: #endif
        !            51: 
        !            52: #ifdef PHP_WIN32
        !            53: #include "win32/unistd.h"
        !            54: #if _MSC_VER <= 1300
        !            55: # include "win32/php_strtoi64.h"
        !            56: #endif
        !            57: #define strtoull _strtoui64
        !            58: #else
        !            59: #include <unistd.h>
        !            60: #endif
        !            61: 
        !            62: #include <string.h>
        !            63: #include <assert.h>
        !            64: #include <ctype.h>
        !            65: #include <fcntl.h>
        !            66: #ifndef PHP_WIN32
        !            67: #include <dirent.h>
        !            68: #endif
        !            69: 
        !            70: #define        EATAB {while (isascii((unsigned char) *l) && \
        !            71:                      isspace((unsigned char) *l))  ++l;}
        !            72: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
        !            73:                        tolower((unsigned char) (l)) : (l))
        !            74: /*
        !            75:  * Work around a bug in headers on Digital Unix.
        !            76:  * At least confirmed for: OSF1 V4.0 878
        !            77:  */
        !            78: #if defined(__osf__) && defined(__DECC)
        !            79: #ifdef MAP_FAILED
        !            80: #undef MAP_FAILED
        !            81: #endif
        !            82: #endif
        !            83: 
        !            84: #ifndef MAP_FAILED
        !            85: #define MAP_FAILED (void *) -1
        !            86: #endif
        !            87: 
        !            88: #ifndef MAP_FILE
        !            89: #define MAP_FILE 0
        !            90: #endif
        !            91: 
        !            92: #ifndef MAXPATHLEN
        !            93: #define MAXPATHLEN     1024
        !            94: #endif
        !            95: 
        !            96: struct magic_entry {
        !            97:        struct magic *mp;       
        !            98:        uint32_t cont_count;
        !            99:        uint32_t max_count;
        !           100: };
        !           101: 
        !           102: int file_formats[FILE_NAMES_SIZE];
        !           103: const size_t file_nformats = FILE_NAMES_SIZE;
        !           104: const char *file_names[FILE_NAMES_SIZE];
        !           105: const size_t file_nnames = FILE_NAMES_SIZE;
        !           106: 
        !           107: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
        !           108: private int hextoint(int);
        !           109: private const char *getstr(struct magic_set *, struct magic *, const char *,
        !           110:     int);
        !           111: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
        !           112:     const char *, size_t, int);
        !           113: private void eatsize(const char **);
        !           114: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
        !           115: private size_t apprentice_magic_strength(const struct magic *);
        !           116: private int apprentice_sort(const void *, const void *);
        !           117: private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
        !           118:     const char *, int);
        !           119: private void byteswap(struct magic *, uint32_t);
        !           120: private void bs1(struct magic *);
        !           121: private uint16_t swap2(uint16_t);
        !           122: private uint32_t swap4(uint32_t);
        !           123: private uint64_t swap8(uint64_t);
        !           124: private char *mkdbname(struct magic_set *, const char *, int);
        !           125: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
        !           126:     const char *);
        !           127: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
        !           128:     const char *);
        !           129: private int check_format_type(const char *, int);
        !           130: private int check_format(struct magic_set *, struct magic *);
        !           131: private int get_op(char);
        !           132: private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
        !           133: private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
        !           134: private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
        !           135: 
        !           136: private size_t maxmagic = 0;
        !           137: private size_t magicsize = sizeof(struct magic);
        !           138: 
        !           139: private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
        !           140: private struct {
        !           141:        const char *name;
        !           142:        size_t len;
        !           143:        int (*fun)(struct magic_set *, struct magic_entry *, const char *);
        !           144: } bang[] = {
        !           145: #define        DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
        !           146:        DECLARE_FIELD(mime),
        !           147:        DECLARE_FIELD(apple),
        !           148:        DECLARE_FIELD(strength),
        !           149: #undef DECLARE_FIELD
        !           150:        { NULL, 0, NULL }
        !           151: };
        !           152: 
        !           153: #include "../data_file.c"
        !           154: 
        !           155: static const struct type_tbl_s {
        !           156:        const char name[16];
        !           157:        const size_t len;
        !           158:        const int type;
        !           159:        const int format;
        !           160: } type_tbl[] = {
        !           161: # define XX(s)         s, (sizeof(s) - 1)
        !           162: # define XX_NULL       "", 0
        !           163:        { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
        !           164:        { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
        !           165:        { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
        !           166:        { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
        !           167:        { XX("string"),         FILE_STRING,            FILE_FMT_STR },
        !           168:        { XX("date"),           FILE_DATE,              FILE_FMT_STR },
        !           169:        { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
        !           170:        { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
        !           171:        { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
        !           172:        { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
        !           173:        { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
        !           174:        { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
        !           175:        { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
        !           176:        { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
        !           177:        { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
        !           178:        { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
        !           179:        { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
        !           180:        { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
        !           181:        { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
        !           182:        { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
        !           183:        { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
        !           184:        { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
        !           185:        { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
        !           186:        { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
        !           187:        { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
        !           188:        { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
        !           189:        { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
        !           190:        { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
        !           191:        { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
        !           192:        { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
        !           193:        { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
        !           194:        { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
        !           195:        { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
        !           196:        { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
        !           197:        { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
        !           198:        { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
        !           199:        { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
        !           200:        { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
        !           201:        { XX("leid3"),          FILE_LEID3,             FILE_FMT_NUM },
        !           202:        { XX("beid3"),          FILE_BEID3,             FILE_FMT_NUM },
        !           203:        { XX("indirect"),       FILE_INDIRECT,          FILE_FMT_NONE },
        !           204:        { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
        !           205: # undef XX
        !           206: # undef XX_NULL
        !           207: };
        !           208: 
        !           209: #ifndef S_ISDIR
        !           210: #define S_ISDIR(mode) ((mode) & _S_IFDIR)
        !           211: #endif
        !           212: 
        !           213: private int
        !           214: get_type(const char *l, const char **t)
        !           215: {
        !           216:        const struct type_tbl_s *p;
        !           217: 
        !           218:        for (p = type_tbl; p->len; p++) {
        !           219:                if (strncmp(l, p->name, p->len) == 0) {
        !           220:                        if (t)
        !           221:                                *t = l + p->len;
        !           222:                        break;
        !           223:                }
        !           224:        }
        !           225:        return p->type;
        !           226: }
        !           227: 
        !           228: private void
        !           229: init_file_tables(void)
        !           230: {
        !           231:        static int done = 0;
        !           232:        const struct type_tbl_s *p;
        !           233: 
        !           234:        if (done)
        !           235:                return;
        !           236:        done++;
        !           237: 
        !           238:        for (p = type_tbl; p->len; p++) {
        !           239:                assert(p->type < FILE_NAMES_SIZE);
        !           240:                file_names[p->type] = p->name;
        !           241:                file_formats[p->type] = p->format;
        !           242:        }
        !           243: }
        !           244: 
        !           245: /*
        !           246:  * Handle one file or directory.
        !           247:  */
        !           248: private int
        !           249: apprentice_1(struct magic_set *ms, const char *fn, int action,
        !           250:     struct mlist *mlist)
        !           251: {
        !           252:        struct magic *magic = NULL;
        !           253:        uint32_t nmagic = 0;
        !           254:        struct mlist *ml;
        !           255:        int rv = -1;
        !           256:        int mapped;
        !           257: 
        !           258:        if (magicsize != FILE_MAGICSIZE) {
        !           259:                file_error(ms, 0, "magic element size %lu != %lu",
        !           260:                    (unsigned long)sizeof(*magic),
        !           261:                    (unsigned long)FILE_MAGICSIZE);
        !           262:                return -1;
        !           263:        }
        !           264: 
        !           265:        if (action == FILE_COMPILE) {
        !           266:                rv = apprentice_load(ms, &magic, &nmagic, fn, action);
        !           267:                if (rv != 0)
        !           268:                        return -1;
        !           269:                rv = apprentice_compile(ms, &magic, &nmagic, fn);
        !           270:                efree(magic);
        !           271:                return rv;
        !           272:        }
        !           273: 
        !           274:        if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
        !           275:                if (fn) {
        !           276:                        if (ms->flags & MAGIC_CHECK)
        !           277:                                file_magwarn(ms, "using regular magic file `%s'", fn);
        !           278:                        rv = apprentice_load(ms, &magic, &nmagic, fn, action);
        !           279:                }
        !           280: 
        !           281:                if (rv != 0)
        !           282:                        return -1;
        !           283:        }
        !           284: 
        !           285:        mapped = rv;
        !           286:             
        !           287:        if (magic == NULL) {
        !           288:                file_delmagic(magic, mapped, nmagic);
        !           289:                return -1;
        !           290:        }
        !           291: 
        !           292:        ml = emalloc(sizeof(*ml));
        !           293: 
        !           294:        ml->magic = magic;
        !           295:        ml->nmagic = nmagic;
        !           296:        ml->mapped = mapped;
        !           297: 
        !           298:        mlist->prev->next = ml;
        !           299:        ml->prev = mlist->prev;
        !           300:        ml->next = mlist;
        !           301:        mlist->prev = ml;
        !           302: 
        !           303:        return 0;
        !           304: }
        !           305: 
        !           306: protected void
        !           307: file_delmagic(struct magic *p, int type, size_t entries)
        !           308: {
        !           309:        if (p == NULL)
        !           310:                return;
        !           311:        switch (type) {
        !           312:        case 3:
        !           313:                /* Do nothing, it's part of the code segment */
        !           314:                break;
        !           315: 
        !           316:        case 1:
        !           317:                p--;
        !           318:                /*FALLTHROUGH*/
        !           319: 
        !           320:        case 0:
        !           321:                efree(p);
        !           322:                break;
        !           323: 
        !           324:        default:
        !           325:                abort();
        !           326:        }
        !           327: }
        !           328: 
        !           329: /* const char *fn: list of magic files and directories */
        !           330: protected struct mlist *
        !           331: file_apprentice(struct magic_set *ms, const char *fn, int action)
        !           332: {
        !           333:        char *p, *mfn;
        !           334:        int file_err, errs = -1;
        !           335:        struct mlist *mlist;
        !           336: 
        !           337:        init_file_tables();
        !           338: 
        !           339:        if (fn == NULL)
        !           340:                fn = getenv("MAGIC");
        !           341:        if (fn == NULL) {
        !           342:                mlist = emalloc(sizeof(*mlist));
        !           343:                mlist->next = mlist->prev = mlist;
        !           344:                apprentice_1(ms, fn, action, mlist);
        !           345:                return mlist;
        !           346:        }
        !           347: 
        !           348:        mfn = estrdup(fn);
        !           349:        fn = mfn;
        !           350: 
        !           351:        mlist = emalloc(sizeof(*mlist));
        !           352:        mlist->next = mlist->prev = mlist;
        !           353: 
        !           354:        while (fn) {
        !           355:                p = strchr(fn, PATHSEP);
        !           356:                if (p)
        !           357:                        *p++ = '\0';
        !           358:                if (*fn == '\0')
        !           359:                        break;
        !           360:                file_err = apprentice_1(ms, fn, action, mlist);
        !           361:                errs = MAX(errs, file_err);
        !           362:                fn = p;
        !           363:        }
        !           364:        if (errs == -1) {
        !           365:                efree(mfn);
        !           366:                efree(mlist);
        !           367:                mlist = NULL;
        !           368:                file_error(ms, 0, "could not find any magic files!");
        !           369:                return NULL;
        !           370:        }
        !           371:        efree(mfn);
        !           372:        return mlist;
        !           373: }
        !           374: 
        !           375: /*
        !           376:  * Get weight of this magic entry, for sorting purposes.
        !           377:  */
        !           378: private size_t
        !           379: apprentice_magic_strength(const struct magic *m)
        !           380: {
        !           381: #define MULT 10
        !           382:        size_t val = 2 * MULT;  /* baseline strength */
        !           383: 
        !           384:        switch (m->type) {
        !           385:        case FILE_DEFAULT:      /* make sure this sorts last */
        !           386:                if (m->factor_op != FILE_FACTOR_OP_NONE)
        !           387:                        abort();
        !           388:                return 0;
        !           389: 
        !           390:        case FILE_BYTE:
        !           391:                val += 1 * MULT;
        !           392:                break;
        !           393: 
        !           394:        case FILE_SHORT:
        !           395:        case FILE_LESHORT:
        !           396:        case FILE_BESHORT:
        !           397:                val += 2 * MULT;
        !           398:                break;
        !           399: 
        !           400:        case FILE_LONG:
        !           401:        case FILE_LELONG:
        !           402:        case FILE_BELONG:
        !           403:        case FILE_MELONG:
        !           404:                val += 4 * MULT;
        !           405:                break;
        !           406: 
        !           407:        case FILE_PSTRING:
        !           408:        case FILE_STRING:
        !           409:                val += m->vallen * MULT;
        !           410:                break;
        !           411: 
        !           412:        case FILE_BESTRING16:
        !           413:        case FILE_LESTRING16:
        !           414:                val += m->vallen * MULT / 2;
        !           415:                break;
        !           416: 
        !           417:        case FILE_SEARCH:
        !           418:        case FILE_REGEX:
        !           419:                val += m->vallen * MAX(MULT / m->vallen, 1);
        !           420:                break;
        !           421: 
        !           422:        case FILE_DATE:
        !           423:        case FILE_LEDATE:
        !           424:        case FILE_BEDATE:
        !           425:        case FILE_MEDATE:
        !           426:        case FILE_LDATE:
        !           427:        case FILE_LELDATE:
        !           428:        case FILE_BELDATE:
        !           429:        case FILE_MELDATE:
        !           430:        case FILE_FLOAT:
        !           431:        case FILE_BEFLOAT:
        !           432:        case FILE_LEFLOAT:
        !           433:                val += 4 * MULT;
        !           434:                break;
        !           435: 
        !           436:        case FILE_QUAD:
        !           437:        case FILE_BEQUAD:
        !           438:        case FILE_LEQUAD:
        !           439:        case FILE_QDATE:
        !           440:        case FILE_LEQDATE:
        !           441:        case FILE_BEQDATE:
        !           442:        case FILE_QLDATE:
        !           443:        case FILE_LEQLDATE:
        !           444:        case FILE_BEQLDATE:
        !           445:        case FILE_DOUBLE:
        !           446:        case FILE_BEDOUBLE:
        !           447:        case FILE_LEDOUBLE:
        !           448:                val += 8 * MULT;
        !           449:                break;
        !           450: 
        !           451:        default:
        !           452:                val = 0;
        !           453:                (void)fprintf(stderr, "Bad type %d\n", m->type);
        !           454:                abort();
        !           455:        }
        !           456: 
        !           457:        switch (m->reln) {
        !           458:        case 'x':       /* matches anything penalize */
        !           459:        case '!':       /* matches almost anything penalize */
        !           460:                val = 0;
        !           461:                break;
        !           462: 
        !           463:        case '=':       /* Exact match, prefer */
        !           464:                val += MULT;
        !           465:                break;
        !           466: 
        !           467:        case '>':
        !           468:        case '<':       /* comparison match reduce strength */
        !           469:                val -= 2 * MULT;
        !           470:                break;
        !           471: 
        !           472:        case '^':
        !           473:        case '&':       /* masking bits, we could count them too */
        !           474:                val -= MULT;
        !           475:                break;
        !           476: 
        !           477:        default:
        !           478:                (void)fprintf(stderr, "Bad relation %c\n", m->reln);
        !           479:                abort();
        !           480:        }
        !           481: 
        !           482:        if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
        !           483:                val = 1;
        !           484: 
        !           485:        switch (m->factor_op) {
        !           486:        case FILE_FACTOR_OP_NONE:
        !           487:                break;
        !           488:        case FILE_FACTOR_OP_PLUS:
        !           489:                val += m->factor;
        !           490:                break;
        !           491:        case FILE_FACTOR_OP_MINUS:
        !           492:                val -= m->factor;
        !           493:                break;
        !           494:        case FILE_FACTOR_OP_TIMES:
        !           495:                val *= m->factor;
        !           496:                break;
        !           497:        case FILE_FACTOR_OP_DIV:
        !           498:                val /= m->factor;
        !           499:                break;
        !           500:        default:
        !           501:                abort();
        !           502:        }
        !           503: 
        !           504: 
        !           505:        /*
        !           506:         * Magic entries with no description get a bonus because they depend
        !           507:         * on subsequent magic entries to print something.
        !           508:         */
        !           509:        if (m->desc[0] == '\0')
        !           510:                val++;
        !           511:        return val;
        !           512: }
        !           513: 
        !           514: /*  
        !           515:  * Sort callback for sorting entries by "strength" (basically length)
        !           516:  */
        !           517: private int
        !           518: apprentice_sort(const void *a, const void *b)
        !           519: {
        !           520:        const struct magic_entry *ma = a;
        !           521:        const struct magic_entry *mb = b;
        !           522:        size_t sa = apprentice_magic_strength(ma->mp);
        !           523:        size_t sb = apprentice_magic_strength(mb->mp);
        !           524:        if (sa == sb)
        !           525:                return 0;
        !           526:        else if (sa > sb)
        !           527:                return -1;
        !           528:        else
        !           529:                return 1;
        !           530: }
        !           531: 
        !           532: private void
        !           533: set_test_type(struct magic *mstart, struct magic *m)
        !           534: {
        !           535:        switch (m->type) {
        !           536:        case FILE_BYTE:
        !           537:        case FILE_SHORT:
        !           538:        case FILE_LONG:
        !           539:        case FILE_DATE:
        !           540:        case FILE_BESHORT:
        !           541:        case FILE_BELONG:
        !           542:        case FILE_BEDATE:
        !           543:        case FILE_LESHORT:
        !           544:        case FILE_LELONG:
        !           545:        case FILE_LEDATE:
        !           546:        case FILE_LDATE:
        !           547:        case FILE_BELDATE:
        !           548:        case FILE_LELDATE:
        !           549:        case FILE_MEDATE:
        !           550:        case FILE_MELDATE:
        !           551:        case FILE_MELONG:
        !           552:        case FILE_QUAD:
        !           553:        case FILE_LEQUAD:
        !           554:        case FILE_BEQUAD:
        !           555:        case FILE_QDATE:
        !           556:        case FILE_LEQDATE:
        !           557:        case FILE_BEQDATE:
        !           558:        case FILE_QLDATE:
        !           559:        case FILE_LEQLDATE:
        !           560:        case FILE_BEQLDATE:
        !           561:        case FILE_FLOAT:
        !           562:        case FILE_BEFLOAT:
        !           563:        case FILE_LEFLOAT:
        !           564:        case FILE_DOUBLE:
        !           565:        case FILE_BEDOUBLE:
        !           566:        case FILE_LEDOUBLE:
        !           567:        case FILE_STRING:
        !           568:        case FILE_PSTRING:
        !           569:        case FILE_BESTRING16:
        !           570:        case FILE_LESTRING16:
        !           571:                /* binary test, set flag */
        !           572:                mstart->flag |= BINTEST;
        !           573:                break;
        !           574:        case FILE_REGEX:
        !           575:        case FILE_SEARCH:
        !           576:                /* binary test if pattern is not text */
        !           577:                if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
        !           578:                    NULL) <= 0)
        !           579:                        mstart->flag |= BINTEST;
        !           580:                break;
        !           581:        case FILE_DEFAULT:
        !           582:                /* can't deduce anything; we shouldn't see this at the
        !           583:                   top level anyway */
        !           584:                break;
        !           585:        case FILE_INVALID:
        !           586:        default:
        !           587:                /* invalid search type, but no need to complain here */
        !           588:                break;
        !           589:        }
        !           590: }
        !           591: 
        !           592: /*
        !           593:  * Load and parse one file.
        !           594:  */
        !           595: private void
        !           596: load_1(struct magic_set *ms, int action, const char *fn, int *errs,
        !           597:    struct magic_entry **marray, uint32_t *marraycount)
        !           598: {
        !           599:        char buffer[BUFSIZ + 1];
        !           600:        char *line;
        !           601:        size_t line_len;
        !           602:        size_t lineno = 0;
        !           603: 
        !           604:        php_stream *stream;
        !           605: 
        !           606:        TSRMLS_FETCH();
        !           607: 
        !           608: #if PHP_API_VERSION < 20100412
        !           609:        stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
        !           610: #else
        !           611:        stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
        !           612: #endif
        !           613: 
        !           614:        if (stream == NULL) {
        !           615:                if (errno != ENOENT)
        !           616:                        file_error(ms, errno, "cannot read magic file `%s'",
        !           617:                                   fn);
        !           618:                (*errs)++;
        !           619:        } else {
        !           620: 
        !           621:                /* read and parse this file */
        !           622: #if (PHP_MAJOR_VERSION < 6)
        !           623:                for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &line_len)) != NULL; ms->line++) {
        !           624: #else          
        !           625:                for (ms->line = 1; (line = php_stream_get_line(stream, ZSTR(buffer), BUFSIZ, &line_len)) != NULL; ms->line++) {
        !           626: #endif
        !           627:                        if (line_len == 0) /* null line, garbage, etc */
        !           628:                                continue;
        !           629: 
        !           630:                        if (line[line_len - 1] == '\n') {
        !           631:                                lineno++;
        !           632:                                line[line_len - 1] = '\0'; /* delete newline */
        !           633:                        }
        !           634:                        if (line[0] == '\0')    /* empty, do not parse */
        !           635:                                continue;
        !           636:                        if (line[0] == '#')     /* comment, do not parse */
        !           637:                                continue;
        !           638: 
        !           639:                        if (line[0] == '!' && line[1] == ':') {
        !           640:                                size_t i;
        !           641: 
        !           642:                                for (i = 0; bang[i].name != NULL; i++) {
        !           643:                                        if (line_len - 2 > bang[i].len &&
        !           644:                                            memcmp(bang[i].name, line + 2,
        !           645:                                            bang[i].len) == 0)
        !           646:                                                break;
        !           647:                                }
        !           648:                                if (bang[i].name == NULL) {
        !           649:                                        file_error(ms, 0,
        !           650:                                            "Unknown !: entry `%s'", line);
        !           651:                                        (*errs)++;
        !           652:                                        continue;
        !           653:                                }
        !           654:                                if (*marraycount == 0) {
        !           655:                                        file_error(ms, 0,
        !           656:                                            "No current entry for :!%s type",
        !           657:                                                bang[i].name);
        !           658:                                        (*errs)++;
        !           659:                                        continue;
        !           660:                                }
        !           661:                                if ((*bang[i].fun)(ms, 
        !           662:                                    &(*marray)[*marraycount - 1],
        !           663:                                    line + bang[i].len + 2) != 0) {
        !           664:                                        (*errs)++;
        !           665:                                        continue;
        !           666:                                }
        !           667:                                continue;
        !           668:                        }
        !           669:                        if (parse(ms, marray, marraycount, line, lineno, action) != 0)
        !           670:                                (*errs)++;
        !           671:                }
        !           672: 
        !           673:                php_stream_close(stream);
        !           674:        }
        !           675: }
        !           676: 
        !           677: /*
        !           678:  * parse a file or directory of files
        !           679:  * const char *fn: name of magic file or directory
        !           680:  */
        !           681: private int
        !           682: apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
        !           683:     const char *fn, int action)
        !           684: {
        !           685:        int errs = 0;
        !           686:        struct magic_entry *marray;
        !           687:        uint32_t marraycount, i, mentrycount = 0, starttest;
        !           688:        char subfn[MAXPATHLEN];
        !           689:        struct stat st;
        !           690:        DIR *dir;
        !           691:        struct dirent *d;
        !           692: 
        !           693:        ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
        !           694: 
        !           695:        maxmagic = MAXMAGIS;
        !           696:        marray = ecalloc(maxmagic, sizeof(*marray));
        !           697:        marraycount = 0;
        !           698: 
        !           699:        /* print silly verbose header for USG compat. */
        !           700:        if (action == FILE_CHECK)
        !           701:                (void)fprintf(stderr, "%s\n", usg_hdr);
        !           702: 
        !           703:        /* load directory or file */
        !           704:         /* FIXME: Read file names and sort them to prevent
        !           705:            non-determinism. See Debian bug #488562. */
        !           706:        if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
        !           707:                dir = opendir(fn);
        !           708:                if (dir) {
        !           709:                        while ((d = readdir(dir)) != NULL) {
        !           710:                                snprintf(subfn, sizeof(subfn), "%s/%s",
        !           711:                                    fn, d->d_name);
        !           712:                                if (stat(subfn, &st) == 0 &&
        !           713:                                        S_ISREG(st.st_mode)) {
        !           714:                                        load_1(ms, action, subfn, &errs,
        !           715:                                            &marray, &marraycount);
        !           716:                                }
        !           717:                        }
        !           718:                        closedir(dir);
        !           719:                } else
        !           720:                        errs++;
        !           721:        } else
        !           722:                load_1(ms, action, fn, &errs, &marray, &marraycount);
        !           723:        if (errs)
        !           724:                goto out;
        !           725: 
        !           726:        /* Set types of tests */
        !           727:        for (i = 0; i < marraycount; ) {
        !           728:                if (marray[i].mp->cont_level != 0) {
        !           729:                        i++;
        !           730:                        continue;
        !           731:                }
        !           732: 
        !           733:                starttest = i;
        !           734:                do {
        !           735:                        static const char text[] = "text";
        !           736:                        static const char binary[] = "binary";
        !           737:                        static const size_t len = sizeof(text);
        !           738:                        set_test_type(marray[starttest].mp, marray[i].mp);
        !           739:                        if ((ms->flags & MAGIC_DEBUG) == 0)
        !           740:                                continue;
        !           741:                        (void)fprintf(stderr, "%s%s%s: %s\n",
        !           742:                            marray[i].mp->mimetype,
        !           743:                            marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
        !           744:                            marray[i].mp->desc[0] ? marray[i].mp->desc :
        !           745:                            "(no description)",
        !           746:                            marray[i].mp->flag & BINTEST ? binary : text);
        !           747:                        if (marray[i].mp->flag & BINTEST) {
        !           748:                                char *p = strstr(marray[i].mp->desc, text);
        !           749:                                if (p && (p == marray[i].mp->desc ||
        !           750:                                    isspace((unsigned char)p[-1])) &&
        !           751:                                    (p + len - marray[i].mp->desc == 
        !           752:                                    MAXstring || (p[len] == '\0' ||
        !           753:                                    isspace((unsigned char)p[len]))))
        !           754:                                        (void)fprintf(stderr, "*** Possible "
        !           755:                                            "binary test for text type\n");
        !           756:                        }
        !           757:                } while (++i < marraycount && marray[i].mp->cont_level != 0);
        !           758:        }
        !           759: 
        !           760:        qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
        !           761: 
        !           762:        /*
        !           763:         * Make sure that any level 0 "default" line is last (if one exists).
        !           764:         */
        !           765:        for (i = 0; i < marraycount; i++) {
        !           766:                if (marray[i].mp->cont_level == 0 &&
        !           767:                    marray[i].mp->type == FILE_DEFAULT) {
        !           768:                        while (++i < marraycount)
        !           769:                                if (marray[i].mp->cont_level == 0)
        !           770:                                        break;
        !           771:                        if (i != marraycount) {
        !           772:                                ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
        !           773:                                file_magwarn(ms,
        !           774:                                    "level 0 \"default\" did not sort last");
        !           775:                        }
        !           776:                        break;                                      
        !           777:                }
        !           778:        }
        !           779: 
        !           780:        for (i = 0; i < marraycount; i++)
        !           781:                mentrycount += marray[i].cont_count;
        !           782: 
        !           783:        *magicp = emalloc(sizeof(**magicp) * mentrycount);
        !           784: 
        !           785:        mentrycount = 0;
        !           786:        for (i = 0; i < marraycount; i++) {
        !           787:                (void)memcpy(*magicp + mentrycount, marray[i].mp,
        !           788:                    marray[i].cont_count * sizeof(**magicp));
        !           789:                mentrycount += marray[i].cont_count;
        !           790:        }
        !           791: out:
        !           792:        for (i = 0; i < marraycount; i++)
        !           793:                efree(marray[i].mp);
        !           794:        efree(marray);
        !           795:        if (errs) {
        !           796:                *magicp = NULL;
        !           797:                *nmagicp = 0;
        !           798:                return errs;
        !           799:        } else {
        !           800:                *nmagicp = mentrycount;
        !           801:                return 0;
        !           802:        }
        !           803: 
        !           804: }
        !           805: 
        !           806: /*
        !           807:  * extend the sign bit if the comparison is to be signed
        !           808:  */
        !           809: protected uint64_t
        !           810: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
        !           811: {
        !           812:        if (!(m->flag & UNSIGNED)) {
        !           813:                switch(m->type) {
        !           814:                /*
        !           815:                 * Do not remove the casts below.  They are
        !           816:                 * vital.  When later compared with the data,
        !           817:                 * the sign extension must have happened.
        !           818:                 */
        !           819:                case FILE_BYTE:
        !           820:                        v = (char) v;
        !           821:                        break;
        !           822:                case FILE_SHORT:
        !           823:                case FILE_BESHORT:
        !           824:                case FILE_LESHORT:
        !           825:                        v = (short) v;
        !           826:                        break;
        !           827:                case FILE_DATE:
        !           828:                case FILE_BEDATE:
        !           829:                case FILE_LEDATE:
        !           830:                case FILE_MEDATE:
        !           831:                case FILE_LDATE:
        !           832:                case FILE_BELDATE:
        !           833:                case FILE_LELDATE:
        !           834:                case FILE_MELDATE:
        !           835:                case FILE_LONG:
        !           836:                case FILE_BELONG:
        !           837:                case FILE_LELONG:
        !           838:                case FILE_MELONG:
        !           839:                case FILE_FLOAT:
        !           840:                case FILE_BEFLOAT:
        !           841:                case FILE_LEFLOAT:
        !           842:                        v = (int32_t) v;
        !           843:                        break;
        !           844:                case FILE_QUAD:
        !           845:                case FILE_BEQUAD:
        !           846:                case FILE_LEQUAD:
        !           847:                case FILE_QDATE:
        !           848:                case FILE_QLDATE:
        !           849:                case FILE_BEQDATE:
        !           850:                case FILE_BEQLDATE:
        !           851:                case FILE_LEQDATE:
        !           852:                case FILE_LEQLDATE:
        !           853:                case FILE_DOUBLE:
        !           854:                case FILE_BEDOUBLE:
        !           855:                case FILE_LEDOUBLE:
        !           856:                        v = (int64_t) v;
        !           857:                        break;
        !           858:                case FILE_STRING:
        !           859:                case FILE_PSTRING:
        !           860:                case FILE_BESTRING16:
        !           861:                case FILE_LESTRING16:
        !           862:                case FILE_REGEX:
        !           863:                case FILE_SEARCH:
        !           864:                case FILE_DEFAULT:
        !           865:                case FILE_INDIRECT:
        !           866:                        break;
        !           867:                default:
        !           868:                        if (ms->flags & MAGIC_CHECK)
        !           869:                            file_magwarn(ms, "cannot happen: m->type=%d\n",
        !           870:                                    m->type);
        !           871:                        return ~0U;
        !           872:                }
        !           873:        }
        !           874:        return v;
        !           875: }
        !           876: 
        !           877: private int
        !           878: string_modifier_check(struct magic_set *ms, struct magic *m)
        !           879: {
        !           880:        if ((ms->flags & MAGIC_CHECK) == 0)
        !           881:                return 0;
        !           882: 
        !           883:        switch (m->type) {
        !           884:        case FILE_BESTRING16:
        !           885:        case FILE_LESTRING16:
        !           886:                if (m->str_flags != 0) {
        !           887:                        file_magwarn(ms,
        !           888:                            "no modifiers allowed for 16-bit strings\n");
        !           889:                        return -1;
        !           890:                }
        !           891:                break;
        !           892:        case FILE_STRING:
        !           893:        case FILE_PSTRING:
        !           894:                if ((m->str_flags & REGEX_OFFSET_START) != 0) {
        !           895:                        file_magwarn(ms,
        !           896:                            "'/%c' only allowed on regex and search\n",
        !           897:                            CHAR_REGEX_OFFSET_START);
        !           898:                        return -1;
        !           899:                }
        !           900:                break;
        !           901:        case FILE_SEARCH:
        !           902:                if (m->str_range == 0) {
        !           903:                        file_magwarn(ms,
        !           904:                            "missing range; defaulting to %d\n",
        !           905:                             STRING_DEFAULT_RANGE);
        !           906:                        m->str_range = STRING_DEFAULT_RANGE;
        !           907:                        return -1;
        !           908:                }
        !           909:                break;
        !           910:        case FILE_REGEX:
        !           911:                if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
        !           912:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
        !           913:                            CHAR_COMPACT_BLANK);
        !           914:                        return -1;
        !           915:                }
        !           916:                if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
        !           917:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
        !           918:                            CHAR_COMPACT_OPTIONAL_BLANK);
        !           919:                        return -1;
        !           920:                }
        !           921:                break;
        !           922:        default:
        !           923:                file_magwarn(ms, "coding error: m->type=%d\n",
        !           924:                    m->type);
        !           925:                return -1;
        !           926:        }
        !           927:        return 0;
        !           928: }
        !           929: 
        !           930: private int
        !           931: get_op(char c)
        !           932: {
        !           933:        switch (c) {
        !           934:        case '&':
        !           935:                return FILE_OPAND;
        !           936:        case '|':
        !           937:                return FILE_OPOR;
        !           938:        case '^':
        !           939:                return FILE_OPXOR;
        !           940:        case '+':
        !           941:                return FILE_OPADD;
        !           942:        case '-':
        !           943:                return FILE_OPMINUS;
        !           944:        case '*':
        !           945:                return FILE_OPMULTIPLY;
        !           946:        case '/':
        !           947:                return FILE_OPDIVIDE;
        !           948:        case '%':
        !           949:                return FILE_OPMODULO;
        !           950:        default:
        !           951:                return -1;
        !           952:        }
        !           953: }
        !           954: 
        !           955: #ifdef ENABLE_CONDITIONALS
        !           956: private int
        !           957: get_cond(const char *l, const char **t)
        !           958: {
        !           959:        static const struct cond_tbl_s {
        !           960:                char name[8];
        !           961:                size_t len;
        !           962:                int cond;
        !           963:        } cond_tbl[] = {
        !           964:                { "if",         2,      COND_IF },
        !           965:                { "elif",       4,      COND_ELIF },
        !           966:                { "else",       4,      COND_ELSE },
        !           967:                { "",           0,      COND_NONE },
        !           968:        };
        !           969:        const struct cond_tbl_s *p;
        !           970: 
        !           971:        for (p = cond_tbl; p->len; p++) {
        !           972:                if (strncmp(l, p->name, p->len) == 0 &&
        !           973:                    isspace((unsigned char)l[p->len])) {
        !           974:                        if (t)
        !           975:                                *t = l + p->len;
        !           976:                        break;
        !           977:                }
        !           978:        }
        !           979:        return p->cond;
        !           980: }
        !           981: 
        !           982: private int
        !           983: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
        !           984: {
        !           985:        int last_cond;
        !           986:        last_cond = ms->c.li[cont_level].last_cond;
        !           987: 
        !           988:        switch (cond) {
        !           989:        case COND_IF:
        !           990:                if (last_cond != COND_NONE && last_cond != COND_ELIF) {
        !           991:                        if (ms->flags & MAGIC_CHECK)
        !           992:                                file_magwarn(ms, "syntax error: `if'");
        !           993:                        return -1;
        !           994:                }
        !           995:                last_cond = COND_IF;
        !           996:                break;
        !           997: 
        !           998:        case COND_ELIF:
        !           999:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
        !          1000:                        if (ms->flags & MAGIC_CHECK)
        !          1001:                                file_magwarn(ms, "syntax error: `elif'");
        !          1002:                        return -1;
        !          1003:                }
        !          1004:                last_cond = COND_ELIF;
        !          1005:                break;
        !          1006: 
        !          1007:        case COND_ELSE:
        !          1008:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
        !          1009:                        if (ms->flags & MAGIC_CHECK)
        !          1010:                                file_magwarn(ms, "syntax error: `else'");
        !          1011:                        return -1;
        !          1012:                }
        !          1013:                last_cond = COND_NONE;
        !          1014:                break;
        !          1015: 
        !          1016:        case COND_NONE:
        !          1017:                last_cond = COND_NONE;
        !          1018:                break;
        !          1019:        }
        !          1020: 
        !          1021:        ms->c.li[cont_level].last_cond = last_cond;
        !          1022:        return 0;
        !          1023: }
        !          1024: #endif /* ENABLE_CONDITIONALS */
        !          1025: 
        !          1026: /*
        !          1027:  * parse one line from magic file, put into magic[index++] if valid
        !          1028:  */
        !          1029: private int
        !          1030: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
        !          1031:     const char *line, size_t lineno, int action)
        !          1032: {
        !          1033: #ifdef ENABLE_CONDITIONALS
        !          1034:        static uint32_t last_cont_level = 0;
        !          1035: #endif
        !          1036:        size_t i;
        !          1037:        struct magic_entry *me;
        !          1038:        struct magic *m;
        !          1039:        const char *l = line;
        !          1040:        char *t;
        !          1041:        int op;
        !          1042:        uint32_t cont_level;
        !          1043: 
        !          1044:        cont_level = 0;
        !          1045: 
        !          1046:        while (*l == '>') {
        !          1047:                ++l;            /* step over */
        !          1048:                cont_level++; 
        !          1049:        }
        !          1050: #ifdef ENABLE_CONDITIONALS
        !          1051:        if (cont_level == 0 || cont_level > last_cont_level)
        !          1052:                if (file_check_mem(ms, cont_level) == -1)
        !          1053:                        return -1;
        !          1054:        last_cont_level = cont_level;
        !          1055: #endif
        !          1056: 
        !          1057: #define ALLOC_CHUNK    (size_t)10
        !          1058: #define ALLOC_INCR     (size_t)200
        !          1059: 
        !          1060:        if (cont_level != 0) {
        !          1061:                if (*nmentryp == 0) {
        !          1062:                        file_error(ms, 0, "No current entry for continuation");
        !          1063:                        return -1;
        !          1064:                }
        !          1065:                me = &(*mentryp)[*nmentryp - 1];
        !          1066:                if (me->cont_count == me->max_count) {
        !          1067:                        struct magic *nm;
        !          1068:                        size_t cnt = me->max_count + ALLOC_CHUNK;
        !          1069:                        nm = erealloc(me->mp, sizeof(*nm) * cnt);
        !          1070:                        me->mp = m = nm;
        !          1071:                        me->max_count = cnt;
        !          1072:                }
        !          1073:                m = &me->mp[me->cont_count++];
        !          1074:                (void)memset(m, 0, sizeof(*m));
        !          1075:                m->cont_level = cont_level;
        !          1076:        } else {
        !          1077:                if (*nmentryp == maxmagic) {
        !          1078:                        struct magic_entry *mp;
        !          1079: 
        !          1080:                        maxmagic += ALLOC_INCR;
        !          1081:                        mp = erealloc(*mentryp, sizeof(*mp) * maxmagic);
        !          1082:                        (void)memset(&mp[*nmentryp], 0, sizeof(*mp) * ALLOC_INCR);
        !          1083:                        *mentryp = mp;
        !          1084:                }
        !          1085:                me = &(*mentryp)[*nmentryp];
        !          1086:                if (me->mp == NULL) {
        !          1087:                        m = safe_emalloc(sizeof(*m), ALLOC_CHUNK, 0);
        !          1088:                        me->mp = m;
        !          1089:                        me->max_count = ALLOC_CHUNK;
        !          1090:                } else
        !          1091:                        m = me->mp;
        !          1092:                (void)memset(m, 0, sizeof(*m));
        !          1093:                m->factor_op = FILE_FACTOR_OP_NONE;
        !          1094:                m->cont_level = 0;
        !          1095:                me->cont_count = 1;
        !          1096:        }
        !          1097:        m->lineno = lineno;
        !          1098: 
        !          1099:        if (*l == '&') {  /* m->cont_level == 0 checked below. */
        !          1100:                 ++l;            /* step over */
        !          1101:                 m->flag |= OFFADD;
        !          1102:         }
        !          1103:        if (*l == '(') {
        !          1104:                ++l;            /* step over */
        !          1105:                m->flag |= INDIR;
        !          1106:                if (m->flag & OFFADD)
        !          1107:                        m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
        !          1108: 
        !          1109:                if (*l == '&') {  /* m->cont_level == 0 checked below */
        !          1110:                        ++l;            /* step over */
        !          1111:                        m->flag |= OFFADD;
        !          1112:                }
        !          1113:        }
        !          1114:        /* Indirect offsets are not valid at level 0. */
        !          1115:        if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
        !          1116:                if (ms->flags & MAGIC_CHECK)
        !          1117:                        file_magwarn(ms, "relative offset at level 0");
        !          1118: 
        !          1119:        /* get offset, then skip over it */
        !          1120:        m->offset = (uint32_t)strtoul(l, &t, 0);
        !          1121:         if (l == t)
        !          1122:                if (ms->flags & MAGIC_CHECK)
        !          1123:                        file_magwarn(ms, "offset `%s' invalid", l);
        !          1124:         l = t;
        !          1125: 
        !          1126:        if (m->flag & INDIR) {
        !          1127:                m->in_type = FILE_LONG;
        !          1128:                m->in_offset = 0;
        !          1129:                /*
        !          1130:                 * read [.lbs][+-]nnnnn)
        !          1131:                 */
        !          1132:                if (*l == '.') {
        !          1133:                        l++;
        !          1134:                        switch (*l) {
        !          1135:                        case 'l':
        !          1136:                                m->in_type = FILE_LELONG;
        !          1137:                                break;
        !          1138:                        case 'L':
        !          1139:                                m->in_type = FILE_BELONG;
        !          1140:                                break;
        !          1141:                        case 'm':
        !          1142:                                m->in_type = FILE_MELONG;
        !          1143:                                break;
        !          1144:                        case 'h':
        !          1145:                        case 's':
        !          1146:                                m->in_type = FILE_LESHORT;
        !          1147:                                break;
        !          1148:                        case 'H':
        !          1149:                        case 'S':
        !          1150:                                m->in_type = FILE_BESHORT;
        !          1151:                                break;
        !          1152:                        case 'c':
        !          1153:                        case 'b':
        !          1154:                        case 'C':
        !          1155:                        case 'B':
        !          1156:                                m->in_type = FILE_BYTE;
        !          1157:                                break;
        !          1158:                        case 'e':
        !          1159:                        case 'f':
        !          1160:                        case 'g':
        !          1161:                                m->in_type = FILE_LEDOUBLE;
        !          1162:                                break;
        !          1163:                        case 'E':
        !          1164:                        case 'F':
        !          1165:                        case 'G':
        !          1166:                                m->in_type = FILE_BEDOUBLE;
        !          1167:                                break;
        !          1168:                        case 'i':
        !          1169:                                m->in_type = FILE_LEID3;
        !          1170:                                break;
        !          1171:                        case 'I':
        !          1172:                                m->in_type = FILE_BEID3;
        !          1173:                                break;
        !          1174:                        default:
        !          1175:                                if (ms->flags & MAGIC_CHECK)
        !          1176:                                        file_magwarn(ms,
        !          1177:                                            "indirect offset type `%c' invalid",
        !          1178:                                            *l);
        !          1179:                                break;
        !          1180:                        }
        !          1181:                        l++;
        !          1182:                }
        !          1183: 
        !          1184:                m->in_op = 0;
        !          1185:                if (*l == '~') {
        !          1186:                        m->in_op |= FILE_OPINVERSE;
        !          1187:                        l++;
        !          1188:                }
        !          1189:                if ((op = get_op(*l)) != -1) {
        !          1190:                        m->in_op |= op;
        !          1191:                        l++;
        !          1192:                }
        !          1193:                if (*l == '(') {
        !          1194:                        m->in_op |= FILE_OPINDIRECT;
        !          1195:                        l++;
        !          1196:                }
        !          1197:                if (isdigit((unsigned char)*l) || *l == '-') {
        !          1198:                        m->in_offset = (int32_t)strtol(l, &t, 0);
        !          1199:                        if (l == t)
        !          1200:                                if (ms->flags & MAGIC_CHECK)
        !          1201:                                        file_magwarn(ms,
        !          1202:                                            "in_offset `%s' invalid", l);
        !          1203:                        l = t;
        !          1204:                }
        !          1205:                if (*l++ != ')' || 
        !          1206:                    ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
        !          1207:                        if (ms->flags & MAGIC_CHECK)
        !          1208:                                file_magwarn(ms,
        !          1209:                                    "missing ')' in indirect offset");
        !          1210:        }
        !          1211:        EATAB;
        !          1212: 
        !          1213: #ifdef ENABLE_CONDITIONALS
        !          1214:        m->cond = get_cond(l, &l);
        !          1215:        if (check_cond(ms, m->cond, cont_level) == -1)
        !          1216:                return -1;
        !          1217: 
        !          1218:        EATAB;
        !          1219: #endif
        !          1220: 
        !          1221:        if (*l == 'u') {
        !          1222:                ++l;
        !          1223:                m->flag |= UNSIGNED;
        !          1224:        }
        !          1225: 
        !          1226:        m->type = get_type(l, &l);
        !          1227:        if (m->type == FILE_INVALID) {
        !          1228:                if (ms->flags & MAGIC_CHECK)
        !          1229:                        file_magwarn(ms, "type `%s' invalid", l);
        !          1230:                return -1;
        !          1231:        }
        !          1232: 
        !          1233:        /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
        !          1234:        /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
        !          1235: 
        !          1236:        m->mask_op = 0;
        !          1237:        if (*l == '~') {
        !          1238:                if (!IS_LIBMAGIC_STRING(m->type))
        !          1239:                        m->mask_op |= FILE_OPINVERSE;
        !          1240:                else if (ms->flags & MAGIC_CHECK)
        !          1241:                        file_magwarn(ms, "'~' invalid for string types");
        !          1242:                ++l;
        !          1243:        }
        !          1244:        m->str_range = 0;
        !          1245:        m->str_flags = 0;
        !          1246:        m->num_mask = 0;
        !          1247:        if ((op = get_op(*l)) != -1) {
        !          1248:                if (!IS_LIBMAGIC_STRING(m->type)) {
        !          1249:                        uint64_t val;
        !          1250:                        ++l;
        !          1251:                        m->mask_op |= op;
        !          1252:                        val = (uint64_t)strtoull(l, &t, 0);
        !          1253:                        l = t;
        !          1254:                        m->num_mask = file_signextend(ms, m, val);
        !          1255:                        eatsize(&l);
        !          1256:                }
        !          1257:                else if (op == FILE_OPDIVIDE) {
        !          1258:                        int have_range = 0;
        !          1259:                        while (!isspace((unsigned char)*++l)) {
        !          1260:                                switch (*l) {
        !          1261:                                case '0':  case '1':  case '2':
        !          1262:                                case '3':  case '4':  case '5':
        !          1263:                                case '6':  case '7':  case '8':
        !          1264:                                case '9':
        !          1265:                                        if (have_range &&
        !          1266:                                            (ms->flags & MAGIC_CHECK))
        !          1267:                                                file_magwarn(ms,
        !          1268:                                                    "multiple ranges");
        !          1269:                                        have_range = 1;
        !          1270:                                        m->str_range = strtoul(l, &t, 0);
        !          1271:                                        if (m->str_range == 0)
        !          1272:                                                file_magwarn(ms,
        !          1273:                                                    "zero range");
        !          1274:                                        l = t - 1;
        !          1275:                                        break;
        !          1276:                                case CHAR_COMPACT_BLANK:
        !          1277:                                        m->str_flags |= STRING_COMPACT_BLANK;
        !          1278:                                        break;
        !          1279:                                case CHAR_COMPACT_OPTIONAL_BLANK:
        !          1280:                                        m->str_flags |=
        !          1281:                                            STRING_COMPACT_OPTIONAL_BLANK;
        !          1282:                                        break;
        !          1283:                                case CHAR_IGNORE_LOWERCASE:
        !          1284:                                        m->str_flags |= STRING_IGNORE_LOWERCASE;
        !          1285:                                        break;
        !          1286:                                case CHAR_IGNORE_UPPERCASE:
        !          1287:                                        m->str_flags |= STRING_IGNORE_UPPERCASE;
        !          1288:                                        break;
        !          1289:                                case CHAR_REGEX_OFFSET_START:
        !          1290:                                        m->str_flags |= REGEX_OFFSET_START;
        !          1291:                                        break;
        !          1292:                                default:
        !          1293:                                        if (ms->flags & MAGIC_CHECK)
        !          1294:                                                file_magwarn(ms,
        !          1295:                                                "string extension `%c' invalid",
        !          1296:                                                *l);
        !          1297:                                        return -1;
        !          1298:                                }
        !          1299:                                /* allow multiple '/' for readability */
        !          1300:                                if (l[1] == '/' &&
        !          1301:                                    !isspace((unsigned char)l[2]))
        !          1302:                                        l++;
        !          1303:                        }
        !          1304:                        if (string_modifier_check(ms, m) == -1)
        !          1305:                                return -1;
        !          1306:                }
        !          1307:                else {
        !          1308:                        if (ms->flags & MAGIC_CHECK)
        !          1309:                                file_magwarn(ms, "invalid string op: %c", *t);
        !          1310:                        return -1;
        !          1311:                }
        !          1312:        }
        !          1313:        /*
        !          1314:         * We used to set mask to all 1's here, instead let's just not do
        !          1315:         * anything if mask = 0 (unless you have a better idea)
        !          1316:         */
        !          1317:        EATAB;
        !          1318:   
        !          1319:        switch (*l) {
        !          1320:        case '>':
        !          1321:        case '<':
        !          1322:                m->reln = *l;
        !          1323:                ++l;
        !          1324:                if (*l == '=') {
        !          1325:                        if (ms->flags & MAGIC_CHECK) {
        !          1326:                                file_magwarn(ms, "%c= not supported",
        !          1327:                                    m->reln);
        !          1328:                                return -1;
        !          1329:                        }
        !          1330:                   ++l;
        !          1331:                }
        !          1332:                break;
        !          1333:        /* Old-style anding: "0 byte &0x80 dynamically linked" */
        !          1334:        case '&':
        !          1335:        case '^':
        !          1336:        case '=':
        !          1337:                m->reln = *l;
        !          1338:                ++l;
        !          1339:                if (*l == '=') {
        !          1340:                   /* HP compat: ignore &= etc. */
        !          1341:                   ++l;
        !          1342:                }
        !          1343:                break;
        !          1344:        case '!':
        !          1345:                m->reln = *l;
        !          1346:                ++l;
        !          1347:                break;
        !          1348:        default:
        !          1349:                m->reln = '=';  /* the default relation */
        !          1350:                if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
        !          1351:                    isspace((unsigned char)l[1])) || !l[1])) {
        !          1352:                        m->reln = *l;
        !          1353:                        ++l;
        !          1354:                }
        !          1355:                break;
        !          1356:        }
        !          1357:        /*
        !          1358:         * Grab the value part, except for an 'x' reln.
        !          1359:         */
        !          1360:        if (m->reln != 'x' && getvalue(ms, m, &l, action))
        !          1361:                return -1;
        !          1362: 
        !          1363:        /*
        !          1364:         * TODO finish this macro and start using it!
        !          1365:         * #define offsetcheck {if (offset > HOWMANY-1) 
        !          1366:         *      magwarn("offset too big"); }
        !          1367:         */
        !          1368: 
        !          1369:        /*
        !          1370:         * Now get last part - the description
        !          1371:         */
        !          1372:        EATAB;
        !          1373:        if (l[0] == '\b') {
        !          1374:                ++l;
        !          1375:                m->flag |= NOSPACE;
        !          1376:        } else if ((l[0] == '\\') && (l[1] == 'b')) {
        !          1377:                ++l;
        !          1378:                ++l;
        !          1379:                m->flag |= NOSPACE;
        !          1380:        }
        !          1381:        for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
        !          1382:                continue;
        !          1383:        if (i == sizeof(m->desc)) {
        !          1384:                m->desc[sizeof(m->desc) - 1] = '\0';
        !          1385:                if (ms->flags & MAGIC_CHECK)
        !          1386:                        file_magwarn(ms, "description `%s' truncated", m->desc);
        !          1387:        }
        !          1388: 
        !          1389:         /*
        !          1390:         * We only do this check while compiling, or if any of the magic
        !          1391:         * files were not compiled.
        !          1392:          */
        !          1393:         if (ms->flags & MAGIC_CHECK) {
        !          1394:                if (check_format(ms, m) == -1)
        !          1395:                        return -1;
        !          1396:        }
        !          1397:        m->mimetype[0] = '\0';          /* initialise MIME type to none */
        !          1398:        if (m->cont_level == 0)
        !          1399:                ++(*nmentryp);          /* make room for next */
        !          1400:        return 0;
        !          1401: }
        !          1402: 
        !          1403: /*
        !          1404:  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
        !          1405:  * if valid
        !          1406:  */
        !          1407: private int
        !          1408: parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
        !          1409: {
        !          1410:        const char *l = line;
        !          1411:        char *el;
        !          1412:        unsigned long factor;
        !          1413:        struct magic *m = &me->mp[0];
        !          1414: 
        !          1415:        if (m->factor_op != FILE_FACTOR_OP_NONE) {
        !          1416:                file_magwarn(ms,
        !          1417:                    "Current entry already has a strength type: %c %d",
        !          1418:                    m->factor_op, m->factor);
        !          1419:                return -1;
        !          1420:        }
        !          1421:        EATAB;
        !          1422:        switch (*l) {
        !          1423:        case FILE_FACTOR_OP_NONE:
        !          1424:        case FILE_FACTOR_OP_PLUS:
        !          1425:        case FILE_FACTOR_OP_MINUS:
        !          1426:        case FILE_FACTOR_OP_TIMES:
        !          1427:        case FILE_FACTOR_OP_DIV:
        !          1428:                m->factor_op = *l++;
        !          1429:                break;
        !          1430:        default:
        !          1431:                file_magwarn(ms, "Unknown factor op `%c'", *l);
        !          1432:                return -1;
        !          1433:        }
        !          1434:        EATAB;
        !          1435:        factor = strtoul(l, &el, 0);
        !          1436:        if (factor > 255) {
        !          1437:                file_magwarn(ms, "Too large factor `%lu'", factor);
        !          1438:                goto out;
        !          1439:        }
        !          1440:        if (*el && !isspace((unsigned char)*el)) {
        !          1441:                file_magwarn(ms, "Bad factor `%s'", l);
        !          1442:                goto out;
        !          1443:        }
        !          1444:        m->factor = (uint8_t)factor;
        !          1445:        if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
        !          1446:                file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
        !          1447:                    m->factor_op, m->factor);
        !          1448:                goto out;
        !          1449:        }
        !          1450:        return 0;
        !          1451: out:
        !          1452:        m->factor_op = FILE_FACTOR_OP_NONE;
        !          1453:        m->factor = 0;
        !          1454:        return -1;
        !          1455: }
        !          1456: 
        !          1457: /*
        !          1458:  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
        !          1459:  */
        !          1460: private int
        !          1461: parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
        !          1462: {
        !          1463:        size_t i;
        !          1464:        const char *l = line;
        !          1465:        struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
        !          1466: 
        !          1467:        if (m->apple[0] != '\0') {
        !          1468:                file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
        !          1469:                    " new type `%s'", m->mimetype, l);
        !          1470:                return -1;
        !          1471:        }       
        !          1472: 
        !          1473:        EATAB;
        !          1474:        for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
        !          1475:             || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
        !          1476:                continue;
        !          1477:        if (i == sizeof(m->apple) && *l) {
        !          1478:                if (ms->flags & MAGIC_CHECK)
        !          1479:                        file_magwarn(ms, "APPLE type `%s' truncated %zu",
        !          1480:                            line, i);
        !          1481:        }
        !          1482: 
        !          1483:        if (i > 0)
        !          1484:                return 0;
        !          1485:        else
        !          1486:                return -1;
        !          1487: }
        !          1488: 
        !          1489: /*
        !          1490:  * parse a MIME annotation line from magic file, put into magic[index - 1]
        !          1491:  * if valid
        !          1492:  */
        !          1493: private int
        !          1494: parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
        !          1495: {
        !          1496:        size_t i;
        !          1497:        const char *l = line;
        !          1498:        struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
        !          1499: 
        !          1500:        if (m->mimetype[0] != '\0') {
        !          1501:                file_magwarn(ms, "Current entry already has a MIME type `%s',"
        !          1502:                    " new type `%s'", m->mimetype, l);
        !          1503:                return -1;
        !          1504:        }       
        !          1505: 
        !          1506:        EATAB;
        !          1507:        for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
        !          1508:             || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
        !          1509:                continue;
        !          1510:        if (i == sizeof(m->mimetype)) {
        !          1511:                m->desc[sizeof(m->mimetype) - 1] = '\0';
        !          1512:                if (ms->flags & MAGIC_CHECK)
        !          1513:                        file_magwarn(ms, "MIME type `%s' truncated %zu",
        !          1514:                            m->mimetype, i);
        !          1515:        } else
        !          1516:                m->mimetype[i] = '\0';
        !          1517: 
        !          1518:        if (i > 0)
        !          1519:                return 0;
        !          1520:        else
        !          1521:                return -1;
        !          1522: }
        !          1523: 
        !          1524: private int
        !          1525: check_format_type(const char *ptr, int type)
        !          1526: {
        !          1527:        int quad = 0;
        !          1528:        if (*ptr == '\0') {
        !          1529:                /* Missing format string; bad */
        !          1530:                return -1;
        !          1531:        }
        !          1532: 
        !          1533:        switch (type) {
        !          1534:        case FILE_FMT_QUAD:
        !          1535:                quad = 1;
        !          1536:                /*FALLTHROUGH*/
        !          1537:        case FILE_FMT_NUM:
        !          1538:                if (*ptr == '-')
        !          1539:                        ptr++;
        !          1540:                if (*ptr == '.')
        !          1541:                        ptr++;
        !          1542:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1543:                if (*ptr == '.')
        !          1544:                        ptr++;
        !          1545:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1546:                if (quad) {
        !          1547:                        if (*ptr++ != 'l')
        !          1548:                                return -1;
        !          1549:                        if (*ptr++ != 'l')
        !          1550:                                return -1;
        !          1551:                }
        !          1552:        
        !          1553:                switch (*ptr++) {
        !          1554:                case 'l':
        !          1555:                        switch (*ptr++) {
        !          1556:                        case 'i':
        !          1557:                        case 'd':
        !          1558:                        case 'u':
        !          1559:                        case 'x':
        !          1560:                        case 'X':
        !          1561:                                return 0;
        !          1562:                        default:
        !          1563:                                return -1;
        !          1564:                        }
        !          1565:                
        !          1566:                case 'h':
        !          1567:                        switch (*ptr++) {
        !          1568:                        case 'h':
        !          1569:                                switch (*ptr++) {
        !          1570:                                case 'i':
        !          1571:                                case 'd':
        !          1572:                                case 'u':
        !          1573:                                case 'x':
        !          1574:                                case 'X':
        !          1575:                                        return 0;
        !          1576:                                default:
        !          1577:                                        return -1;
        !          1578:                                }
        !          1579:                        case 'd':
        !          1580:                                return 0;
        !          1581:                        default:
        !          1582:                                return -1;
        !          1583:                        }
        !          1584: 
        !          1585:                case 'i':
        !          1586:                case 'c':
        !          1587:                case 'd':
        !          1588:                case 'u':
        !          1589:                case 'x':
        !          1590:                case 'X':
        !          1591:                        return 0;
        !          1592:                        
        !          1593:                default:
        !          1594:                        return -1;
        !          1595:                }
        !          1596:                
        !          1597:        case FILE_FMT_FLOAT:
        !          1598:        case FILE_FMT_DOUBLE:
        !          1599:                if (*ptr == '-')
        !          1600:                        ptr++;
        !          1601:                if (*ptr == '.')
        !          1602:                        ptr++;
        !          1603:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1604:                if (*ptr == '.')
        !          1605:                        ptr++;
        !          1606:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1607:        
        !          1608:                switch (*ptr++) {
        !          1609:                case 'e':
        !          1610:                case 'E':
        !          1611:                case 'f':
        !          1612:                case 'F':
        !          1613:                case 'g':
        !          1614:                case 'G':
        !          1615:                        return 0;
        !          1616:                        
        !          1617:                default:
        !          1618:                        return -1;
        !          1619:                }
        !          1620:                
        !          1621: 
        !          1622:        case FILE_FMT_STR:
        !          1623:                if (*ptr == '-')
        !          1624:                        ptr++;
        !          1625:                while (isdigit((unsigned char )*ptr))
        !          1626:                        ptr++;
        !          1627:                if (*ptr == '.') {
        !          1628:                        ptr++;
        !          1629:                        while (isdigit((unsigned char )*ptr))
        !          1630:                                ptr++;
        !          1631:                }
        !          1632:                
        !          1633:                switch (*ptr++) {
        !          1634:                case 's':
        !          1635:                        return 0;
        !          1636:                default:
        !          1637:                        return -1;
        !          1638:                }
        !          1639:                
        !          1640:        default:
        !          1641:                /* internal error */
        !          1642:                abort();
        !          1643:        }
        !          1644:        /*NOTREACHED*/
        !          1645:        return -1;
        !          1646: }
        !          1647:        
        !          1648: /*
        !          1649:  * Check that the optional printf format in description matches
        !          1650:  * the type of the magic.
        !          1651:  */
        !          1652: private int
        !          1653: check_format(struct magic_set *ms, struct magic *m)
        !          1654: {
        !          1655:        char *ptr;
        !          1656: 
        !          1657:        for (ptr = m->desc; *ptr; ptr++)
        !          1658:                if (*ptr == '%')
        !          1659:                        break;
        !          1660:        if (*ptr == '\0') {
        !          1661:                /* No format string; ok */
        !          1662:                return 1;
        !          1663:        }
        !          1664: 
        !          1665:        assert(file_nformats == file_nnames);
        !          1666: 
        !          1667:        if (m->type >= file_nformats) {
        !          1668:                file_magwarn(ms, "Internal error inconsistency between "
        !          1669:                    "m->type and format strings");              
        !          1670:                return -1;
        !          1671:        }
        !          1672:        if (file_formats[m->type] == FILE_FMT_NONE) {
        !          1673:                file_magwarn(ms, "No format string for `%s' with description "
        !          1674:                    "`%s'", m->desc, file_names[m->type]);
        !          1675:                return -1;
        !          1676:        }
        !          1677: 
        !          1678:        ptr++;
        !          1679:        if (check_format_type(ptr, file_formats[m->type]) == -1) {
        !          1680:                /*
        !          1681:                 * TODO: this error message is unhelpful if the format
        !          1682:                 * string is not one character long
        !          1683:                 */
        !          1684:                file_magwarn(ms, "Printf format `%c' is not valid for type "
        !          1685:                    "`%s' in description `%s'", *ptr ? *ptr : '?',
        !          1686:                    file_names[m->type], m->desc);
        !          1687:                return -1;
        !          1688:        }
        !          1689:        
        !          1690:        for (; *ptr; ptr++) {
        !          1691:                if (*ptr == '%') {
        !          1692:                        file_magwarn(ms,
        !          1693:                            "Too many format strings (should have at most one) "
        !          1694:                            "for `%s' with description `%s'",
        !          1695:                            file_names[m->type], m->desc);
        !          1696:                        return -1;
        !          1697:                }
        !          1698:        }
        !          1699:        return 0;
        !          1700: }
        !          1701: 
        !          1702: /* 
        !          1703:  * Read a numeric value from a pointer, into the value union of a magic 
        !          1704:  * pointer, according to the magic type.  Update the string pointer to point 
        !          1705:  * just after the number read.  Return 0 for success, non-zero for failure.
        !          1706:  */
        !          1707: private int
        !          1708: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
        !          1709: {
        !          1710:        switch (m->type) {
        !          1711:        case FILE_BESTRING16:
        !          1712:        case FILE_LESTRING16:
        !          1713:        case FILE_STRING:
        !          1714:        case FILE_PSTRING:
        !          1715:        case FILE_REGEX:
        !          1716:        case FILE_SEARCH:
        !          1717:                *p = getstr(ms, m, *p, action == FILE_COMPILE);
        !          1718:                if (*p == NULL) {
        !          1719:                        if (ms->flags & MAGIC_CHECK)
        !          1720:                                file_magwarn(ms, "cannot get string from `%s'",
        !          1721:                                    m->value.s);
        !          1722:                        return -1;
        !          1723:                }
        !          1724:                return 0;
        !          1725:        case FILE_FLOAT:
        !          1726:        case FILE_BEFLOAT:
        !          1727:        case FILE_LEFLOAT:
        !          1728:                if (m->reln != 'x') {
        !          1729:                        char *ep;
        !          1730: #ifdef HAVE_STRTOF
        !          1731:                        m->value.f = strtof(*p, &ep);
        !          1732: #else
        !          1733:                        m->value.f = (float)strtod(*p, &ep);
        !          1734: #endif
        !          1735:                        *p = ep;
        !          1736:                }
        !          1737:                return 0;
        !          1738:        case FILE_DOUBLE:
        !          1739:        case FILE_BEDOUBLE:
        !          1740:        case FILE_LEDOUBLE:
        !          1741:                if (m->reln != 'x') {
        !          1742:                        char *ep;
        !          1743:                        m->value.d = strtod(*p, &ep);
        !          1744:                        *p = ep;
        !          1745:                }
        !          1746:                return 0;
        !          1747:        default:
        !          1748:                if (m->reln != 'x') {
        !          1749:                        char *ep;
        !          1750:                        m->value.q = file_signextend(ms, m,
        !          1751:                            (uint64_t)strtoull(*p, &ep, 0));
        !          1752:                        *p = ep;
        !          1753:                        eatsize(p);
        !          1754:                }
        !          1755:                return 0;
        !          1756:        }
        !          1757: }
        !          1758: 
        !          1759: /*
        !          1760:  * Convert a string containing C character escapes.  Stop at an unescaped
        !          1761:  * space or tab.
        !          1762:  * Copy the converted version to "m->value.s", and the length in m->vallen.
        !          1763:  * Return updated scan pointer as function result. Warn if set.
        !          1764:  */
        !          1765: private const char *
        !          1766: getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
        !          1767: {
        !          1768:        const char *origs = s;
        !          1769:        char    *p = m->value.s;
        !          1770:        size_t  plen = sizeof(m->value.s);
        !          1771:        char    *origp = p;
        !          1772:        char    *pmax = p + plen - 1;
        !          1773:        int     c;
        !          1774:        int     val;
        !          1775: 
        !          1776:        while ((c = *s++) != '\0') {
        !          1777:                if (isspace((unsigned char) c))
        !          1778:                        break;
        !          1779:                if (p >= pmax) {
        !          1780:                        file_error(ms, 0, "string too long: `%s'", origs);
        !          1781:                        return NULL;
        !          1782:                }
        !          1783:                if (c == '\\') {
        !          1784:                        switch(c = *s++) {
        !          1785: 
        !          1786:                        case '\0':
        !          1787:                                if (warn)
        !          1788:                                        file_magwarn(ms, "incomplete escape");
        !          1789:                                goto out;
        !          1790: 
        !          1791:                        case '\t':
        !          1792:                                if (warn) {
        !          1793:                                        file_magwarn(ms,
        !          1794:                                            "escaped tab found, use \\t instead");
        !          1795:                                        warn = 0;       /* already did */
        !          1796:                                }
        !          1797:                                /*FALLTHROUGH*/
        !          1798:                        default:
        !          1799:                                if (warn) {
        !          1800:                                        if (isprint((unsigned char)c)) {
        !          1801:                                                /* Allow escaping of 
        !          1802:                                                 * ``relations'' */
        !          1803:                                                if (strchr("<>&^=!", c)
        !          1804:                                                    == NULL) {
        !          1805:                                                        file_magwarn(ms, "no "
        !          1806:                                                            "need to escape "
        !          1807:                                                            "`%c'", c);
        !          1808:                                                }
        !          1809:                                        } else {
        !          1810:                                                file_magwarn(ms,
        !          1811:                                                    "unknown escape sequence: "
        !          1812:                                                    "\\%03o", c);
        !          1813:                                        }
        !          1814:                                }
        !          1815:                                /*FALLTHROUGH*/
        !          1816:                        /* space, perhaps force people to use \040? */
        !          1817:                        case ' ':
        !          1818: #if 0
        !          1819:                        /*
        !          1820:                         * Other things people escape, but shouldn't need to,
        !          1821:                         * so we disallow them
        !          1822:                         */
        !          1823:                        case '\'':
        !          1824:                        case '"':
        !          1825:                        case '?':
        !          1826: #endif
        !          1827:                        /* Relations */
        !          1828:                        case '>':
        !          1829:                        case '<':
        !          1830:                        case '&':
        !          1831:                        case '^':
        !          1832:                        case '=':
        !          1833:                        case '!':
        !          1834:                        /* and baskslash itself */
        !          1835:                        case '\\':
        !          1836:                                *p++ = (char) c;
        !          1837:                                break;
        !          1838: 
        !          1839:                        case 'a':
        !          1840:                                *p++ = '\a';
        !          1841:                                break;
        !          1842: 
        !          1843:                        case 'b':
        !          1844:                                *p++ = '\b';
        !          1845:                                break;
        !          1846: 
        !          1847:                        case 'f':
        !          1848:                                *p++ = '\f';
        !          1849:                                break;
        !          1850: 
        !          1851:                        case 'n':
        !          1852:                                *p++ = '\n';
        !          1853:                                break;
        !          1854: 
        !          1855:                        case 'r':
        !          1856:                                *p++ = '\r';
        !          1857:                                break;
        !          1858: 
        !          1859:                        case 't':
        !          1860:                                *p++ = '\t';
        !          1861:                                break;
        !          1862: 
        !          1863:                        case 'v':
        !          1864:                                *p++ = '\v';
        !          1865:                                break;
        !          1866: 
        !          1867:                        /* \ and up to 3 octal digits */
        !          1868:                        case '0':
        !          1869:                        case '1':
        !          1870:                        case '2':
        !          1871:                        case '3':
        !          1872:                        case '4':
        !          1873:                        case '5':
        !          1874:                        case '6':
        !          1875:                        case '7':
        !          1876:                                val = c - '0';
        !          1877:                                c = *s++;  /* try for 2 */
        !          1878:                                if (c >= '0' && c <= '7') {
        !          1879:                                        val = (val << 3) | (c - '0');
        !          1880:                                        c = *s++;  /* try for 3 */
        !          1881:                                        if (c >= '0' && c <= '7')
        !          1882:                                                val = (val << 3) | (c-'0');
        !          1883:                                        else
        !          1884:                                                --s;
        !          1885:                                }
        !          1886:                                else
        !          1887:                                        --s;
        !          1888:                                *p++ = (char)val;
        !          1889:                                break;
        !          1890: 
        !          1891:                        /* \x and up to 2 hex digits */
        !          1892:                        case 'x':
        !          1893:                                val = 'x';      /* Default if no digits */
        !          1894:                                c = hextoint(*s++);     /* Get next char */
        !          1895:                                if (c >= 0) {
        !          1896:                                        val = c;
        !          1897:                                        c = hextoint(*s++);
        !          1898:                                        if (c >= 0)
        !          1899:                                                val = (val << 4) + c;
        !          1900:                                        else
        !          1901:                                                --s;
        !          1902:                                } else
        !          1903:                                        --s;
        !          1904:                                *p++ = (char)val;
        !          1905:                                break;
        !          1906:                        }
        !          1907:                } else
        !          1908:                        *p++ = (char)c;
        !          1909:        }
        !          1910: out:
        !          1911:        *p = '\0';
        !          1912:        m->vallen = p - origp;
        !          1913:        if (m->type == FILE_PSTRING)
        !          1914:                m->vallen++;
        !          1915:        return s;
        !          1916: }
        !          1917: 
        !          1918: 
        !          1919: /* Single hex char to int; -1 if not a hex char. */
        !          1920: private int
        !          1921: hextoint(int c)
        !          1922: {
        !          1923:        if (!isascii((unsigned char) c))
        !          1924:                return -1;
        !          1925:        if (isdigit((unsigned char) c))
        !          1926:                return c - '0';
        !          1927:        if ((c >= 'a') && (c <= 'f'))
        !          1928:                return c + 10 - 'a';
        !          1929:        if (( c>= 'A') && (c <= 'F'))
        !          1930:                return c + 10 - 'A';
        !          1931:        return -1;
        !          1932: }
        !          1933: 
        !          1934: 
        !          1935: /*
        !          1936:  * Print a string containing C character escapes.
        !          1937:  */
        !          1938: protected void
        !          1939: file_showstr(FILE *fp, const char *s, size_t len)
        !          1940: {
        !          1941:        char    c;
        !          1942: 
        !          1943:        for (;;) {
        !          1944:                c = *s++;
        !          1945:                if (len == ~0U) {
        !          1946:                        if (c == '\0')
        !          1947:                                break;
        !          1948:                }
        !          1949:                else  {
        !          1950:                        if (len-- == 0)
        !          1951:                                break;
        !          1952:                }
        !          1953:                if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
        !          1954:                        (void) fputc(c, fp);
        !          1955:                else {
        !          1956:                        (void) fputc('\\', fp);
        !          1957:                        switch (c) {
        !          1958:                        case '\a':
        !          1959:                                (void) fputc('a', fp);
        !          1960:                                break;
        !          1961: 
        !          1962:                        case '\b':
        !          1963:                                (void) fputc('b', fp);
        !          1964:                                break;
        !          1965: 
        !          1966:                        case '\f':
        !          1967:                                (void) fputc('f', fp);
        !          1968:                                break;
        !          1969: 
        !          1970:                        case '\n':
        !          1971:                                (void) fputc('n', fp);
        !          1972:                                break;
        !          1973: 
        !          1974:                        case '\r':
        !          1975:                                (void) fputc('r', fp);
        !          1976:                                break;
        !          1977: 
        !          1978:                        case '\t':
        !          1979:                                (void) fputc('t', fp);
        !          1980:                                break;
        !          1981: 
        !          1982:                        case '\v':
        !          1983:                                (void) fputc('v', fp);
        !          1984:                                break;
        !          1985: 
        !          1986:                        default:
        !          1987:                                (void) fprintf(fp, "%.3o", c & 0377);
        !          1988:                                break;
        !          1989:                        }
        !          1990:                }
        !          1991:        }
        !          1992: }
        !          1993: 
        !          1994: /*
        !          1995:  * eatsize(): Eat the size spec from a number [eg. 10UL]
        !          1996:  */
        !          1997: private void
        !          1998: eatsize(const char **p)
        !          1999: {
        !          2000:        const char *l = *p;
        !          2001: 
        !          2002:        if (LOWCASE(*l) == 'u') 
        !          2003:                l++;
        !          2004: 
        !          2005:        switch (LOWCASE(*l)) {
        !          2006:        case 'l':    /* long */
        !          2007:        case 's':    /* short */
        !          2008:        case 'h':    /* short */
        !          2009:        case 'b':    /* char/byte */
        !          2010:        case 'c':    /* char/byte */
        !          2011:                l++;
        !          2012:                /*FALLTHROUGH*/
        !          2013:        default:
        !          2014:                break;
        !          2015:        }
        !          2016: 
        !          2017:        *p = l;
        !          2018: }
        !          2019: 
        !          2020: /*
        !          2021:  * handle a compiled file.
        !          2022:  * return -1 = error
        !          2023:  * return 1  = memory structure you can free
        !          2024:  * return 3  = bundled library from PHP
        !          2025:  */
        !          2026: private int
        !          2027: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
        !          2028:     const char *fn)
        !          2029: {
        !          2030:        uint32_t *ptr;
        !          2031:        uint32_t version;
        !          2032:        int needsbyteswap;
        !          2033:        char *dbname = NULL;
        !          2034:        void *mm = NULL;
        !          2035:        int   ret = 0;
        !          2036:        php_stream *stream = NULL;
        !          2037:        php_stream_statbuf st;
        !          2038: 
        !          2039: 
        !          2040:        TSRMLS_FETCH();
        !          2041: 
        !          2042:        if (fn == NULL) {
        !          2043:                mm = (void *)&php_magic_database;
        !          2044:                ret = 3;
        !          2045:                goto internal_loaded;
        !          2046:        }
        !          2047: 
        !          2048:        dbname = mkdbname(ms, fn, 0);
        !          2049:        if (dbname == NULL)
        !          2050:                goto error2;
        !          2051: 
        !          2052: #if PHP_API_VERSION < 20100412
        !          2053:                stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
        !          2054: #else
        !          2055:                stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL);
        !          2056: #endif
        !          2057: 
        !          2058:        if (!stream) {
        !          2059:                goto error2;
        !          2060:        }
        !          2061: 
        !          2062:        if (php_stream_stat(stream, &st) < 0) {
        !          2063:                file_error(ms, errno, "cannot stat `%s'", dbname);
        !          2064:                goto error1;
        !          2065:        }
        !          2066: 
        !          2067:        if (st.sb.st_size < 8) {
        !          2068:                file_error(ms, 0, "file `%s' is too small", dbname);
        !          2069:                goto error1;
        !          2070:        }
        !          2071: 
        !          2072:        mm = emalloc((size_t)st.sb.st_size);
        !          2073:        ret = 1;
        !          2074:        if (php_stream_read(stream, mm, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) {
        !          2075:                file_badread(ms);
        !          2076:                goto error1;
        !          2077:        }
        !          2078: 
        !          2079:        php_stream_close(stream);
        !          2080:        stream = NULL;
        !          2081: 
        !          2082: internal_loaded:
        !          2083:        *magicp = mm;
        !          2084:        ptr = (uint32_t *)(void *)*magicp;
        !          2085:        if (*ptr != MAGICNO) {
        !          2086:                if (swap4(*ptr) != MAGICNO) {
        !          2087:                        file_error(ms, 0, "bad magic in `%s'", dbname);
        !          2088:                        goto error1;
        !          2089:                }
        !          2090:                needsbyteswap = 1;
        !          2091:        } else {
        !          2092:                needsbyteswap = 0;
        !          2093:        }
        !          2094: 
        !          2095:        if (needsbyteswap)
        !          2096:                version = swap4(ptr[1]);
        !          2097:        else
        !          2098:                version = ptr[1];
        !          2099: 
        !          2100:        if (version != VERSIONNO) {
        !          2101:                file_error(ms, 0, "File %d.%d supports only version %d magic "
        !          2102:                    "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
        !          2103:                    VERSIONNO, dbname, version);
        !          2104:                goto error1;
        !          2105:        }
        !          2106: 
        !          2107:        /* php_magic_database is a const, performing writes will segfault. This is for big-endian
        !          2108:        machines only, PPC and Sparc specifically. Consider static variable or MINIT in
        !          2109:        future. */
        !          2110:        if (needsbyteswap && fn == NULL) {
        !          2111:                mm = emalloc(sizeof(php_magic_database));
        !          2112:                mm = memcpy(mm, php_magic_database, sizeof(php_magic_database));
        !          2113:                *magicp = mm;
        !          2114:                ret = 1;
        !          2115:        }
        !          2116: 
        !          2117:        if (fn == NULL) {
        !          2118:                *nmagicp = (sizeof(php_magic_database) / sizeof(struct magic));
        !          2119:        } else {
        !          2120:                *nmagicp = (uint32_t)(st.sb.st_size / sizeof(struct magic));
        !          2121:        }
        !          2122:        if (*nmagicp > 0) {
        !          2123:                (*nmagicp)--;
        !          2124:        }
        !          2125:        (*magicp)++;
        !          2126:        if (needsbyteswap) {
        !          2127:                byteswap(*magicp, *nmagicp);
        !          2128:        }
        !          2129: 
        !          2130:        if (dbname) {
        !          2131:                efree(dbname);
        !          2132:        }
        !          2133:        return ret;
        !          2134: 
        !          2135: error1:
        !          2136:        if (stream) {
        !          2137:                php_stream_close(stream);
        !          2138:        }
        !          2139: 
        !          2140:        if (mm && ret == 1) {
        !          2141:                efree(mm);
        !          2142:        } else {
        !          2143:                *magicp = NULL;
        !          2144:                *nmagicp = 0;
        !          2145:        }
        !          2146: error2:
        !          2147:        if (dbname) {
        !          2148:                efree(dbname);
        !          2149:        }
        !          2150:        return -1;
        !          2151: }
        !          2152: 
        !          2153: private const uint32_t ar[] = {
        !          2154:     MAGICNO, VERSIONNO
        !          2155: };
        !          2156: /*
        !          2157:  * handle an mmaped file.
        !          2158:  */
        !          2159: private int
        !          2160: apprentice_compile(struct magic_set *ms, struct magic **magicp,
        !          2161:     uint32_t *nmagicp, const char *fn)
        !          2162: {
        !          2163:        char *dbname;
        !          2164:        int rv = -1;
        !          2165:        php_stream *stream;
        !          2166: 
        !          2167:        TSRMLS_FETCH();
        !          2168: 
        !          2169:        dbname = mkdbname(ms, fn, 0);
        !          2170: 
        !          2171:        if (dbname == NULL) {
        !          2172:                goto out;
        !          2173:        }
        !          2174: 
        !          2175: /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */
        !          2176: #if PHP_API_VERSION < 20100412
        !          2177:        stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
        !          2178: #else
        !          2179:        stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL);
        !          2180: #endif
        !          2181: 
        !          2182:        if (!stream) {
        !          2183:                file_error(ms, errno, "cannot open `%s'", dbname);
        !          2184:                goto out;
        !          2185:        }
        !          2186: 
        !          2187:        if (php_stream_write(stream, (char *)ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
        !          2188:                file_error(ms, errno, "error writing `%s'", dbname);
        !          2189:                goto out;
        !          2190:        }
        !          2191: 
        !          2192:        if (php_stream_seek(stream,(off_t)sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
        !          2193:                file_error(ms, errno, "error seeking `%s'", dbname);
        !          2194:                goto out;
        !          2195:        }
        !          2196: 
        !          2197:        if (php_stream_write(stream, (char *)*magicp, (sizeof(struct magic) * *nmagicp) != (ssize_t)(sizeof(struct magic) * *nmagicp))) {
        !          2198:                file_error(ms, errno, "error writing `%s'", dbname);
        !          2199:                goto out;
        !          2200:        }
        !          2201: 
        !          2202:        php_stream_close(stream);
        !          2203: 
        !          2204:        rv = 0;
        !          2205: out:
        !          2206:        efree(dbname);
        !          2207:        return rv;
        !          2208: }
        !          2209: 
        !          2210: private const char ext[] = ".mgc";
        !          2211: /*
        !          2212:  * make a dbname
        !          2213:  */
        !          2214: private char *
        !          2215: mkdbname(struct magic_set *ms, const char *fn, int strip)
        !          2216: {
        !          2217:        const char *p, *q;
        !          2218:        char *buf;
        !          2219:        TSRMLS_FETCH();
        !          2220: 
        !          2221:        if (strip) {
        !          2222:                if ((p = strrchr(fn, '/')) != NULL)
        !          2223:                        fn = ++p;
        !          2224:        }
        !          2225: 
        !          2226:        for (q = fn; *q; q++)
        !          2227:                continue;
        !          2228:        /* Look for .mgc */
        !          2229:        for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
        !          2230:                if (*p != *q)
        !          2231:                        break;
        !          2232: 
        !          2233:        /* Did not find .mgc, restore q */
        !          2234:        if (p >= ext)
        !          2235:                while (*q)
        !          2236:                        q++;
        !          2237: 
        !          2238:        q++;
        !          2239:        /* Compatibility with old code that looked in .mime */
        !          2240:        if (ms->flags & MAGIC_MIME) {
        !          2241:                spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", (int)(q - fn), fn, ext);
        !          2242:                if (VCWD_ACCESS(buf, R_OK) != -1) {
        !          2243:                        ms->flags &= MAGIC_MIME_TYPE;
        !          2244:                        return buf;
        !          2245:                }
        !          2246:                efree(buf);
        !          2247:        }
        !          2248:        spprintf(&buf, MAXPATHLEN, "%.*s%s", (int)(q - fn), fn, ext);
        !          2249: 
        !          2250:        /* Compatibility with old code that looked in .mime */
        !          2251:        if (strstr(p, ".mime") != NULL)
        !          2252:                ms->flags &= MAGIC_MIME_TYPE;
        !          2253:        return buf;
        !          2254: }
        !          2255: 
        !          2256: /*
        !          2257:  * Byteswap an mmap'ed file if needed
        !          2258:  */
        !          2259: private void
        !          2260: byteswap(struct magic *magic, uint32_t nmagic)
        !          2261: {
        !          2262:        uint32_t i;
        !          2263:        for (i = 0; i < nmagic; i++)
        !          2264:                bs1(&magic[i]);
        !          2265: }
        !          2266: 
        !          2267: /*
        !          2268:  * swap a short
        !          2269:  */
        !          2270: private uint16_t
        !          2271: swap2(uint16_t sv)
        !          2272: {
        !          2273:        uint16_t rv;
        !          2274:        uint8_t *s = (uint8_t *)(void *)&sv; 
        !          2275:        uint8_t *d = (uint8_t *)(void *)&rv; 
        !          2276:        d[0] = s[1];
        !          2277:        d[1] = s[0];
        !          2278:        return rv;
        !          2279: }
        !          2280: 
        !          2281: /*
        !          2282:  * swap an int
        !          2283:  */
        !          2284: private uint32_t
        !          2285: swap4(uint32_t sv)
        !          2286: {
        !          2287:        uint32_t rv;
        !          2288:        uint8_t *s = (uint8_t *)(void *)&sv; 
        !          2289:        uint8_t *d = (uint8_t *)(void *)&rv; 
        !          2290:        d[0] = s[3];
        !          2291:        d[1] = s[2];
        !          2292:        d[2] = s[1];
        !          2293:        d[3] = s[0];
        !          2294:        return rv;
        !          2295: }
        !          2296: 
        !          2297: /*
        !          2298:  * swap a quad
        !          2299:  */
        !          2300: private uint64_t
        !          2301: swap8(uint64_t sv)
        !          2302: {
        !          2303:        uint64_t rv;
        !          2304:        uint8_t *s = (uint8_t *)(void *)&sv; 
        !          2305:        uint8_t *d = (uint8_t *)(void *)&rv; 
        !          2306: #if 0
        !          2307:        d[0] = s[3];
        !          2308:        d[1] = s[2];
        !          2309:        d[2] = s[1];
        !          2310:        d[3] = s[0];
        !          2311:        d[4] = s[7];
        !          2312:        d[5] = s[6];
        !          2313:        d[6] = s[5];
        !          2314:        d[7] = s[4];
        !          2315: #else
        !          2316:        d[0] = s[7];
        !          2317:        d[1] = s[6];
        !          2318:        d[2] = s[5];
        !          2319:        d[3] = s[4];
        !          2320:        d[4] = s[3];
        !          2321:        d[5] = s[2];
        !          2322:        d[6] = s[1];
        !          2323:        d[7] = s[0];
        !          2324: #endif
        !          2325:        return rv;
        !          2326: }
        !          2327: 
        !          2328: /*
        !          2329:  * byteswap a single magic entry
        !          2330:  */
        !          2331: private void
        !          2332: bs1(struct magic *m)
        !          2333: {
        !          2334:        m->cont_level = swap2(m->cont_level);
        !          2335:        m->offset = swap4((uint32_t)m->offset);
        !          2336:        m->in_offset = swap4((uint32_t)m->in_offset);
        !          2337:        m->lineno = swap4((uint32_t)m->lineno);
        !          2338:        if (IS_LIBMAGIC_STRING(m->type)) {
        !          2339:                m->str_range = swap4(m->str_range);
        !          2340:                m->str_flags = swap4(m->str_flags);
        !          2341:        }
        !          2342:        else {
        !          2343:                m->value.q = swap8(m->value.q);
        !          2344:                m->num_mask = swap8(m->num_mask);
        !          2345:        }
        !          2346: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>