[BACK]Return to magic-test.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / file

Annotation of src/usr.bin/file/magic-test.c, Revision 1.25

1.25    ! nicm        1: /* $OpenBSD: magic-test.c,v 1.24 2016/08/26 08:50:31 guenther Exp $ */
1.1       nicm        2:
                      3: /*
                      4:  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
                     15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
                     16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20:
                     21: #include <ctype.h>
                     22: #include <errno.h>
                     23: #include <fcntl.h>
                     24: #include <limits.h>
                     25: #include <stdarg.h>
                     26: #include <stdio.h>
                     27: #include <stdint.h>
                     28: #include <stdlib.h>
                     29: #include <string.h>
1.24      guenther   30: #include <time.h>
1.1       nicm       31: #include <unistd.h>
                     32: #include <vis.h>
                     33:
                     34: #include "magic.h"
                     35: #include "xmalloc.h"
                     36:
1.22      nicm       37: static int magic_test_line(struct magic_line *, struct magic_state *);
                     38:
                     39: static struct magic_line *
                     40: magic_get_named(struct magic *m, const char *name)
                     41: {
                     42:        struct magic_line       ml;
                     43:
                     44:        ml.name = name;
                     45:        return (RB_FIND(magic_named_tree, &m->named, &ml));
                     46: }
                     47:
                     48: static enum magic_type
                     49: magic_reverse_type(struct magic_state *ms, enum magic_type type)
                     50: {
                     51:        if (!ms->reverse)
                     52:                return (type);
                     53:        switch (type) {
                     54:        case MAGIC_TYPE_BESHORT:
                     55:                return (MAGIC_TYPE_LESHORT);
                     56:        case MAGIC_TYPE_BELONG:
                     57:                return (MAGIC_TYPE_LELONG);
                     58:        case MAGIC_TYPE_BEQUAD:
                     59:                return (MAGIC_TYPE_LEQUAD);
                     60:        case MAGIC_TYPE_UBESHORT:
                     61:                return (MAGIC_TYPE_ULESHORT);
                     62:        case MAGIC_TYPE_UBELONG:
                     63:                return (MAGIC_TYPE_ULELONG);
                     64:        case MAGIC_TYPE_UBEQUAD:
                     65:                return (MAGIC_TYPE_ULEQUAD);
                     66:        case MAGIC_TYPE_BEFLOAT:
                     67:                return (MAGIC_TYPE_LEFLOAT);
                     68:        case MAGIC_TYPE_BEDOUBLE:
                     69:                return (MAGIC_TYPE_LEDOUBLE);
                     70:        case MAGIC_TYPE_BEDATE:
                     71:                return (MAGIC_TYPE_LEDATE);
                     72:        case MAGIC_TYPE_BEQDATE:
                     73:                return (MAGIC_TYPE_LEQDATE);
                     74:        case MAGIC_TYPE_BELDATE:
                     75:                return (MAGIC_TYPE_LELDATE);
                     76:        case MAGIC_TYPE_BEQLDATE:
                     77:                return (MAGIC_TYPE_LEQLDATE);
                     78:        case MAGIC_TYPE_UBEDATE:
                     79:                return (MAGIC_TYPE_ULEDATE);
                     80:        case MAGIC_TYPE_UBEQDATE:
                     81:                return (MAGIC_TYPE_ULEQDATE);
                     82:        case MAGIC_TYPE_UBELDATE:
                     83:                return (MAGIC_TYPE_ULELDATE);
                     84:        case MAGIC_TYPE_UBEQLDATE:
                     85:                return (MAGIC_TYPE_ULEQLDATE);
                     86:        case MAGIC_TYPE_LESHORT:
                     87:                return (MAGIC_TYPE_BESHORT);
                     88:        case MAGIC_TYPE_LELONG:
                     89:                return (MAGIC_TYPE_LELONG);
                     90:        case MAGIC_TYPE_LEQUAD:
                     91:                return (MAGIC_TYPE_LEQUAD);
                     92:        case MAGIC_TYPE_ULESHORT:
                     93:                return (MAGIC_TYPE_UBESHORT);
                     94:        case MAGIC_TYPE_ULELONG:
                     95:                return (MAGIC_TYPE_UBELONG);
                     96:        case MAGIC_TYPE_ULEQUAD:
                     97:                return (MAGIC_TYPE_UBEQUAD);
                     98:        case MAGIC_TYPE_LEFLOAT:
                     99:                return (MAGIC_TYPE_BEFLOAT);
                    100:        case MAGIC_TYPE_LEDOUBLE:
                    101:                return (MAGIC_TYPE_BEDOUBLE);
                    102:        case MAGIC_TYPE_LEDATE:
                    103:                return (MAGIC_TYPE_BEDATE);
                    104:        case MAGIC_TYPE_LEQDATE:
                    105:                return (MAGIC_TYPE_BEQDATE);
                    106:        case MAGIC_TYPE_LELDATE:
                    107:                return (MAGIC_TYPE_BELDATE);
                    108:        case MAGIC_TYPE_LEQLDATE:
                    109:                return (MAGIC_TYPE_BEQLDATE);
                    110:        case MAGIC_TYPE_ULEDATE:
                    111:                return (MAGIC_TYPE_UBEDATE);
                    112:        case MAGIC_TYPE_ULEQDATE:
                    113:                return (MAGIC_TYPE_UBEQDATE);
                    114:        case MAGIC_TYPE_ULELDATE:
                    115:                return (MAGIC_TYPE_UBELDATE);
                    116:        case MAGIC_TYPE_ULEQLDATE:
                    117:                return (MAGIC_TYPE_UBEQLDATE);
                    118:        default:
                    119:                return (type);
                    120:        }
                    121: }
                    122:
1.1       nicm      123: static int
                    124: magic_one_eq(char a, char b, int cflag)
                    125: {
                    126:        if (a == b)
                    127:                return (1);
1.4       nicm      128:        if (cflag && islower((u_char)b) && tolower((u_char)a) == (u_char)b)
1.1       nicm      129:                return (1);
                    130:        return (0);
                    131: }
                    132:
                    133: static int
                    134: magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
                    135:     int cflag, int bflag, int Bflag)
                    136: {
                    137:        size_t  aoff, boff, aspaces, bspaces;
                    138:
                    139:        aoff = boff = 0;
                    140:        while (aoff != asize && boff != bsize) {
                    141:                if (Bflag && isspace((u_char)ap[aoff])) {
                    142:                        aspaces = 0;
                    143:                        while (aoff != asize && isspace((u_char)ap[aoff])) {
                    144:                                aspaces++;
                    145:                                aoff++;
                    146:                        }
                    147:                        bspaces = 0;
                    148:                        while (boff != bsize && isspace((u_char)bp[boff])) {
                    149:                                bspaces++;
                    150:                                boff++;
                    151:                        }
                    152:                        if (bspaces >= aspaces)
                    153:                                continue;
                    154:                        return (1);
                    155:                }
                    156:                if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
                    157:                        aoff++;
                    158:                        boff++;
                    159:                        continue;
                    160:                }
                    161:                if (bflag && isspace((u_char)bp[boff])) {
                    162:                        boff++;
                    163:                        continue;
                    164:                }
                    165:                if (ap[aoff] < bp[boff])
                    166:                        return (-1);
                    167:                return (1);
                    168:        }
                    169:        return (0);
                    170: }
                    171:
                    172: static int
                    173: magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
                    174: {
                    175:        if (offset < 0)
                    176:                offset = ms->offset;
                    177:        if (offset + size > ms->size)
                    178:                return (-1);
                    179:        memcpy(dst, ms->base + offset, size);
                    180:        return (0);
                    181: }
                    182:
                    183: static void
                    184: magic_add_result(struct magic_state *ms, struct magic_line *ml,
                    185:     const char *fmt, ...)
                    186: {
                    187:        va_list  ap;
                    188:        int      separate;
                    189:        char    *s, *tmp, *add;
                    190:
                    191:        va_start(ap, fmt);
                    192:        if (ml->stringify) {
                    193:                if (vasprintf(&s, fmt, ap) == -1) {
                    194:                        va_end(ap);
                    195:                        return;
                    196:                }
                    197:                va_end(ap);
                    198:                if (asprintf(&tmp, ml->result, s) == -1) {
                    199:                        free(s);
                    200:                        return;
                    201:                }
                    202:                free(s);
                    203:        } else {
                    204:                if (vasprintf(&tmp, ml->result, ap) == -1) {
                    205:                        va_end(ap);
                    206:                        return;
                    207:                }
                    208:                va_end(ap);
                    209:        }
                    210:
                    211:        separate = 1;
                    212:        if (tmp[0] == '\\' && tmp[1] == 'b') {
                    213:                separate = 0;
                    214:                add = tmp + 2;
                    215:        } else
                    216:                add = tmp;
                    217:
                    218:        if (separate && *ms->out != '\0')
                    219:                strlcat(ms->out, " ", sizeof ms->out);
                    220:        strlcat(ms->out, add, sizeof ms->out);
                    221:
                    222:        free(tmp);
                    223: }
                    224:
                    225: static void
                    226: magic_add_string(struct magic_state *ms, struct magic_line *ml,
1.2       deraadt   227:     const char *s, size_t slen)
1.1       nicm      228: {
                    229:        char    *out;
                    230:        size_t   outlen, offset;
                    231:
                    232:        outlen = MAGIC_STRING_SIZE;
                    233:        if (outlen > slen)
                    234:                outlen = slen;
                    235:        for (offset = 0; offset < outlen; offset++) {
                    236:                if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
                    237:                        outlen = offset;
                    238:                        break;
                    239:                }
                    240:        }
                    241:        out = xreallocarray(NULL, 4, outlen + 1);
                    242:        strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
                    243:        magic_add_result(ms, ml, "%s", out);
                    244:        free(out);
                    245: }
                    246:
                    247: static int
                    248: magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
                    249: {
                    250:        switch (ml->test_operator) {
                    251:        case 'x':
                    252:                return (1);
                    253:        case '<':
                    254:                return (value < wanted);
                    255:        case '[':
                    256:                return (value <= wanted);
                    257:        case '>':
                    258:                return (value > wanted);
                    259:        case ']':
                    260:                return (value >= wanted);
                    261:        case '=':
                    262:                return (value == wanted);
                    263:        case '&':
                    264:                return ((value & wanted) == wanted);
                    265:        case '^':
                    266:                return ((~value & wanted) == wanted);
                    267:        }
                    268:        return (-1);
                    269: }
                    270:
                    271: static int
                    272: magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
                    273: {
                    274:        switch (ml->test_operator) {
                    275:        case 'x':
                    276:                return (1);
                    277:        case '<':
                    278:                return (value < wanted);
                    279:        case '[':
                    280:                return (value <= wanted);
                    281:        case '>':
                    282:                return (value > wanted);
                    283:        case ']':
                    284:                return (value >= wanted);
                    285:        case '=':
                    286:                return (value == wanted);
                    287:        case '&':
                    288:                return ((value & wanted) == wanted);
                    289:        case '^':
                    290:                return ((~value & wanted) == wanted);
                    291:        }
                    292:        return (-1);
                    293: }
                    294:
                    295: static int
1.7       nicm      296: magic_test_double(struct magic_line *ml, double value, double wanted)
                    297: {
                    298:        switch (ml->test_operator) {
                    299:        case 'x':
                    300:                return (1);
                    301:        case '=':
                    302:                return (value == wanted);
                    303:        }
                    304:        return (-1);
                    305: }
                    306:
                    307: static int
1.1       nicm      308: magic_test_type_none(__unused struct magic_line *ml,
                    309:     __unused struct magic_state *ms)
                    310: {
                    311:        return (0);
                    312: }
                    313:
                    314: static int
                    315: magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
                    316: {
                    317:        int8_t  value;
                    318:        int     result;
                    319:
                    320:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    321:                return (0);
                    322:
                    323:        if (ml->type_operator == '&')
                    324:                value &= (int8_t)ml->type_operand;
1.8       nicm      325:        else if (ml->type_operator == '-')
                    326:                value -= (int8_t)ml->type_operand;
                    327:        else if (ml->type_operator == '+')
                    328:                value += (int8_t)ml->type_operand;
                    329:        else if (ml->type_operator == '/')
                    330:                value /= (int8_t)ml->type_operand;
                    331:        else if (ml->type_operator == '%')
                    332:                value %= (int8_t)ml->type_operand;
                    333:        else if (ml->type_operator == '*')
                    334:                value *= (int8_t)ml->type_operand;
1.1       nicm      335:        else if (ml->type_operator != ' ')
                    336:                return (-1);
                    337:
                    338:        result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
                    339:        if (result == !ml->test_not && ml->result != NULL) {
                    340:                magic_add_result(ms, ml, "%c", (int)value);
                    341:                ms->offset += sizeof value;
                    342:        }
                    343:        return (result);
                    344: }
                    345:
                    346: static int
                    347: magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
                    348: {
                    349:        int16_t value;
                    350:        int     result;
                    351:
                    352:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    353:                return (0);
1.22      nicm      354:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BESHORT))
1.3       brynet    355:                value = be16toh(value);
1.22      nicm      356:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LESHORT))
1.3       brynet    357:                value = le16toh(value);
1.1       nicm      358:
                    359:        if (ml->type_operator == '&')
                    360:                value &= (int16_t)ml->type_operand;
1.8       nicm      361:        else if (ml->type_operator == '-')
                    362:                value -= (int16_t)ml->type_operand;
                    363:        else if (ml->type_operator == '+')
                    364:                value += (int16_t)ml->type_operand;
                    365:        else if (ml->type_operator == '/')
                    366:                value /= (int16_t)ml->type_operand;
                    367:        else if (ml->type_operator == '%')
                    368:                value %= (int16_t)ml->type_operand;
                    369:        else if (ml->type_operator == '*')
                    370:                value *= (int16_t)ml->type_operand;
1.1       nicm      371:        else if (ml->type_operator != ' ')
                    372:                return (-1);
                    373:
                    374:        result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
                    375:        if (result == !ml->test_not && ml->result != NULL) {
                    376:                magic_add_result(ms, ml, "%hd", (int)value);
                    377:                ms->offset += sizeof value;
                    378:        }
                    379:        return (result);
                    380: }
                    381:
                    382: static int
                    383: magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
                    384: {
                    385:        int32_t value;
                    386:        int     result;
                    387:
                    388:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    389:                return (0);
1.22      nicm      390:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELONG))
1.3       brynet    391:                value = be32toh(value);
1.22      nicm      392:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELONG))
1.3       brynet    393:                value = le32toh(value);
1.1       nicm      394:
                    395:        if (ml->type_operator == '&')
                    396:                value &= (int32_t)ml->type_operand;
1.8       nicm      397:        else if (ml->type_operator == '-')
                    398:                value -= (int32_t)ml->type_operand;
                    399:        else if (ml->type_operator == '+')
                    400:                value += (int32_t)ml->type_operand;
                    401:        else if (ml->type_operator == '/')
                    402:                value /= (int32_t)ml->type_operand;
                    403:        else if (ml->type_operator == '%')
                    404:                value %= (int32_t)ml->type_operand;
                    405:        else if (ml->type_operator == '*')
                    406:                value *= (int32_t)ml->type_operand;
1.1       nicm      407:        else if (ml->type_operator != ' ')
                    408:                return (-1);
                    409:
                    410:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    411:        if (result == !ml->test_not && ml->result != NULL) {
                    412:                magic_add_result(ms, ml, "%d", (int)value);
                    413:                ms->offset += sizeof value;
                    414:        }
                    415:        return (result);
                    416: }
                    417:
                    418: static int
                    419: magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
                    420: {
                    421:        int64_t value;
                    422:        int     result;
                    423:
                    424:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    425:                return (0);
1.22      nicm      426:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQUAD))
1.3       brynet    427:                value = be64toh(value);
1.22      nicm      428:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQUAD))
1.3       brynet    429:                value = le64toh(value);
1.1       nicm      430:
                    431:        if (ml->type_operator == '&')
                    432:                value &= (int64_t)ml->type_operand;
1.8       nicm      433:        else if (ml->type_operator == '-')
                    434:                value -= (int64_t)ml->type_operand;
                    435:        else if (ml->type_operator == '+')
                    436:                value += (int64_t)ml->type_operand;
                    437:        else if (ml->type_operator == '/')
                    438:                value /= (int64_t)ml->type_operand;
                    439:        else if (ml->type_operator == '%')
                    440:                value %= (int64_t)ml->type_operand;
                    441:        else if (ml->type_operator == '*')
                    442:                value *= (int64_t)ml->type_operand;
1.1       nicm      443:        else if (ml->type_operator != ' ')
                    444:                return (-1);
                    445:
                    446:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    447:        if (result == !ml->test_not && ml->result != NULL) {
                    448:                magic_add_result(ms, ml, "%lld", (long long)value);
                    449:                ms->offset += sizeof value;
                    450:        }
                    451:        return (result);
                    452: }
                    453:
                    454: static int
                    455: magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
                    456: {
                    457:        uint8_t value;
                    458:        int     result;
                    459:
                    460:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    461:                return (0);
                    462:
                    463:        if (ml->type_operator == '&')
                    464:                value &= (uint8_t)ml->type_operand;
1.8       nicm      465:        else if (ml->type_operator == '-')
                    466:                value -= (uint8_t)ml->type_operand;
                    467:        else if (ml->type_operator == '+')
                    468:                value += (uint8_t)ml->type_operand;
                    469:        else if (ml->type_operator == '/')
                    470:                value /= (uint8_t)ml->type_operand;
                    471:        else if (ml->type_operator == '%')
                    472:                value %= (uint8_t)ml->type_operand;
                    473:        else if (ml->type_operator == '*')
                    474:                value *= (uint8_t)ml->type_operand;
1.1       nicm      475:        else if (ml->type_operator != ' ')
                    476:                return (-1);
                    477:
                    478:        result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
                    479:        if (result == !ml->test_not && ml->result != NULL) {
                    480:                magic_add_result(ms, ml, "%c", (unsigned int)value);
                    481:                ms->offset += sizeof value;
                    482:        }
                    483:        return (result);
                    484: }
                    485:
                    486: static int
                    487: magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
                    488: {
                    489:        uint16_t        value;
                    490:        int             result;
                    491:
                    492:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    493:                return (0);
                    494:        if (ml->type == MAGIC_TYPE_UBESHORT)
1.3       brynet    495:                value = be16toh(value);
1.1       nicm      496:        if (ml->type == MAGIC_TYPE_ULESHORT)
1.3       brynet    497:                value = le16toh(value);
1.1       nicm      498:
                    499:        if (ml->type_operator == '&')
                    500:                value &= (uint16_t)ml->type_operand;
1.8       nicm      501:        else if (ml->type_operator == '-')
                    502:                value -= (uint16_t)ml->type_operand;
                    503:        else if (ml->type_operator == '+')
                    504:                value += (uint16_t)ml->type_operand;
                    505:        else if (ml->type_operator == '/')
                    506:                value /= (uint16_t)ml->type_operand;
                    507:        else if (ml->type_operator == '%')
                    508:                value %= (uint16_t)ml->type_operand;
                    509:        else if (ml->type_operator == '*')
                    510:                value *= (uint16_t)ml->type_operand;
1.1       nicm      511:        else if (ml->type_operator != ' ')
                    512:                return (-1);
                    513:
                    514:        result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
                    515:        if (result == !ml->test_not && ml->result != NULL) {
                    516:                magic_add_result(ms, ml, "%hu", (unsigned int)value);
                    517:                ms->offset += sizeof value;
                    518:        }
                    519:        return (result);
                    520: }
                    521:
                    522: static int
                    523: magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
                    524: {
                    525:        uint32_t        value;
                    526:        int             result;
                    527:
                    528:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    529:                return (0);
                    530:        if (ml->type == MAGIC_TYPE_UBELONG)
1.3       brynet    531:                value = be32toh(value);
1.1       nicm      532:        if (ml->type == MAGIC_TYPE_ULELONG)
1.3       brynet    533:                value = le32toh(value);
1.1       nicm      534:
                    535:        if (ml->type_operator == '&')
                    536:                value &= (uint32_t)ml->type_operand;
1.8       nicm      537:        else if (ml->type_operator == '-')
                    538:                value -= (uint32_t)ml->type_operand;
                    539:        else if (ml->type_operator == '+')
                    540:                value += (uint32_t)ml->type_operand;
                    541:        else if (ml->type_operator == '/')
                    542:                value /= (uint32_t)ml->type_operand;
                    543:        else if (ml->type_operator == '%')
                    544:                value %= (uint32_t)ml->type_operand;
                    545:        else if (ml->type_operator == '*')
                    546:                value *= (uint32_t)ml->type_operand;
1.1       nicm      547:        else if (ml->type_operator != ' ')
                    548:                return (-1);
                    549:
                    550:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    551:        if (result == !ml->test_not && ml->result != NULL) {
                    552:                magic_add_result(ms, ml, "%u", (unsigned int)value);
                    553:                ms->offset += sizeof value;
                    554:        }
                    555:        return (result);
                    556: }
                    557:
                    558: static int
                    559: magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
                    560: {
                    561:        uint64_t        value;
                    562:        int             result;
                    563:
                    564:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    565:                return (0);
                    566:        if (ml->type == MAGIC_TYPE_UBEQUAD)
1.3       brynet    567:                value = be64toh(value);
1.1       nicm      568:        if (ml->type == MAGIC_TYPE_ULEQUAD)
1.3       brynet    569:                value = le64toh(value);
1.1       nicm      570:
                    571:        if (ml->type_operator == '&')
                    572:                value &= (uint64_t)ml->type_operand;
1.8       nicm      573:        else if (ml->type_operator == '-')
                    574:                value -= (uint64_t)ml->type_operand;
                    575:        else if (ml->type_operator == '+')
                    576:                value += (uint64_t)ml->type_operand;
                    577:        else if (ml->type_operator == '/')
                    578:                value /= (uint64_t)ml->type_operand;
                    579:        else if (ml->type_operator == '%')
                    580:                value %= (uint64_t)ml->type_operand;
                    581:        else if (ml->type_operator == '*')
                    582:                value *= (uint64_t)ml->type_operand;
1.1       nicm      583:        else if (ml->type_operator != ' ')
                    584:                return (-1);
                    585:
                    586:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    587:        if (result == !ml->test_not && ml->result != NULL) {
                    588:                magic_add_result(ms, ml, "%llu", (unsigned long long)value);
                    589:                ms->offset += sizeof value;
                    590:        }
                    591:        return (result);
                    592: }
                    593:
                    594: static int
                    595: magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
                    596: {
                    597:        uint32_t        value0;
1.16      nicm      598:        float           value;
1.7       nicm      599:        int             result;
1.1       nicm      600:
                    601:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    602:                return (0);
1.22      nicm      603:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEFLOAT))
1.3       brynet    604:                value0 = be32toh(value0);
1.22      nicm      605:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEFLOAT))
1.3       brynet    606:                value0 = le32toh(value0);
1.1       nicm      607:        memcpy(&value, &value0, sizeof value);
                    608:
                    609:        if (ml->type_operator != ' ')
                    610:                return (-1);
                    611:
1.7       nicm      612:        result = magic_test_double(ml, value, (float)ml->test_double);
                    613:        if (result == !ml->test_not && ml->result != NULL) {
                    614:                magic_add_result(ms, ml, "%g", value);
                    615:                ms->offset += sizeof value0;
                    616:        }
1.1       nicm      617:        return (1);
                    618: }
                    619:
                    620: static int
                    621: magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
                    622: {
                    623:        uint64_t        value0;
                    624:        double          value;
1.7       nicm      625:        int             result;
1.1       nicm      626:
                    627:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    628:                return (0);
1.22      nicm      629:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDOUBLE))
1.3       brynet    630:                value0 = be64toh(value0);
1.22      nicm      631:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDOUBLE))
1.3       brynet    632:                value0 = le64toh(value0);
1.1       nicm      633:        memcpy(&value, &value0, sizeof value);
                    634:
                    635:        if (ml->type_operator != ' ')
                    636:                return (-1);
                    637:
1.7       nicm      638:        result = magic_test_double(ml, value, (double)ml->test_double);
                    639:        if (result == !ml->test_not && ml->result != NULL) {
                    640:                magic_add_result(ms, ml, "%g", value);
                    641:                ms->offset += sizeof value0;
                    642:        }
1.1       nicm      643:        return (1);
                    644: }
                    645:
                    646: static int
                    647: magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
                    648: {
                    649:        const char      *s, *cp;
                    650:        size_t           slen;
                    651:        int              result, cflag = 0, bflag = 0, Bflag = 0;
                    652:
                    653:        cp = &ml->type_string[(sizeof "string") - 1];
                    654:        if (*cp != '\0') {
                    655:                if (*cp != '/')
                    656:                        return (-1);
                    657:                cp++;
                    658:                for (; *cp != '\0'; cp++) {
                    659:                        switch (*cp) {
                    660:                        case 'B':
1.11      nicm      661:                        case 'W':
1.1       nicm      662:                                Bflag = 1;
                    663:                                break;
                    664:                        case 'b':
1.11      nicm      665:                        case 'w':
1.1       nicm      666:                                bflag = 1;
                    667:                                break;
                    668:                        case 'c':
                    669:                                cflag = 1;
                    670:                                break;
1.11      nicm      671:                        case 't':
                    672:                                break;
1.1       nicm      673:                        default:
                    674:                                return (-1);
                    675:                        }
                    676:                }
                    677:        }
                    678:
                    679:        s = ms->base + ms->offset;
                    680:        slen = ms->size - ms->offset;
                    681:        if (slen < ml->test_string_size)
                    682:                return (0);
                    683:
                    684:        result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
                    685:            cflag, bflag, Bflag);
                    686:        switch (ml->test_operator) {
                    687:        case 'x':
                    688:                result = 1;
                    689:                break;
                    690:        case '<':
                    691:                result = result < 0;
                    692:                break;
                    693:        case '>':
                    694:                result = result > 0;
                    695:                break;
                    696:        case '=':
1.10      nicm      697:                slen = ml->test_string_size; /* only print what was found */
1.1       nicm      698:                result = result == 0;
                    699:                break;
                    700:        default:
                    701:                result = -1;
                    702:                break;
                    703:        }
                    704:        if (result == !ml->test_not) {
                    705:                if (ml->result != NULL)
                    706:                        magic_add_string(ms, ml, s, slen);
                    707:                if (result && ml->test_operator == '=')
                    708:                        ms->offset = s - ms->base + ml->test_string_size;
                    709:        }
                    710:        return (result);
                    711: }
                    712:
                    713: static int
                    714: magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
                    715: {
1.9       nicm      716:        const char      *s, *cp;
1.1       nicm      717:        size_t           slen;
                    718:        int              result;
1.9       nicm      719:
                    720:        cp = &ml->type_string[(sizeof "pstring") - 1];
                    721:        if (*cp != '\0') {
                    722:                if (*cp != '/')
                    723:                        return (-1);
                    724:                cp++;
                    725:                for (; *cp != '\0'; cp++) {
                    726:                        switch (*cp) {
                    727:                        default:
                    728:                                return (-1);
                    729:                        }
                    730:                }
                    731:        }
1.1       nicm      732:
                    733:        s = ms->base + ms->offset;
                    734:        if (ms->size - ms->offset < 1)
                    735:                return (-1);
                    736:        slen = *(u_char *)s;
1.23      nicm      737:        if (slen + 1 > ms->size - ms->offset)
1.1       nicm      738:                return (-1);
                    739:        s++;
                    740:
                    741:        if (slen < ml->test_string_size)
                    742:                result = -1;
                    743:        else if (slen > ml->test_string_size)
                    744:                result = 1;
                    745:        else
                    746:                result = memcmp(s, ml->test_string, ml->test_string_size);
                    747:        switch (ml->test_operator) {
                    748:        case 'x':
                    749:                result = 1;
                    750:                break;
                    751:        case '<':
                    752:                result = result < 0;
                    753:                break;
                    754:        case '>':
                    755:                result = result > 0;
                    756:                break;
                    757:        case '=':
                    758:                result = result == 0;
                    759:                break;
                    760:        default:
                    761:                result = -1;
                    762:                break;
                    763:        }
                    764:        if (result == !ml->test_not) {
                    765:                if (ml->result != NULL)
                    766:                        magic_add_string(ms, ml, s, slen);
1.12      nicm      767:                if (result && ml->test_operator == '=')
1.1       nicm      768:                        ms->offset += slen + 1;
                    769:        }
                    770:        return (result);
                    771: }
                    772:
                    773: static int
                    774: magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
                    775: {
                    776:        int32_t value;
                    777:        int     result;
                    778:        time_t  t;
                    779:        char    s[64];
                    780:
                    781:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    782:                return (0);
1.22      nicm      783:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDATE) ||
                    784:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELDATE))
1.3       brynet    785:                value = be32toh(value);
1.22      nicm      786:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDATE) ||
                    787:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELDATE))
1.3       brynet    788:                value = le32toh(value);
1.1       nicm      789:
                    790:        if (ml->type_operator == '&')
                    791:                value &= (int32_t)ml->type_operand;
1.13      nicm      792:        else if (ml->type_operator == '-')
                    793:                value -= (int32_t)ml->type_operand;
                    794:        else if (ml->type_operator == '+')
                    795:                value += (int32_t)ml->type_operand;
1.1       nicm      796:        else if (ml->type_operator != ' ')
                    797:                return (-1);
                    798:
                    799:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    800:        if (result == !ml->test_not && ml->result != NULL) {
                    801:                t = value;
                    802:                switch (ml->type) {
                    803:                case MAGIC_TYPE_LDATE:
                    804:                case MAGIC_TYPE_LELDATE:
                    805:                case MAGIC_TYPE_BELDATE:
                    806:                        ctime_r(&t, s);
                    807:                        break;
                    808:                default:
1.6       nicm      809:                        asctime_r(gmtime(&t), s);
1.1       nicm      810:                        break;
                    811:                }
                    812:                s[strcspn(s, "\n")] = '\0';
                    813:                magic_add_result(ms, ml, "%s", s);
                    814:                ms->offset += sizeof value;
                    815:        }
                    816:        return (result);
                    817: }
                    818:
                    819: static int
                    820: magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
                    821: {
                    822:        int64_t value;
                    823:        int     result;
                    824:        time_t  t;
                    825:        char    s[64];
                    826:
                    827:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    828:                return (0);
1.22      nicm      829:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQDATE) ||
                    830:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEQLDATE))
1.3       brynet    831:                value = be64toh(value);
1.22      nicm      832:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQDATE) ||
                    833:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEQLDATE))
1.3       brynet    834:                value = le64toh(value);
1.1       nicm      835:
                    836:        if (ml->type_operator == '&')
                    837:                value &= (int64_t)ml->type_operand;
1.13      nicm      838:        else if (ml->type_operator == '-')
                    839:                value -= (int64_t)ml->type_operand;
                    840:        else if (ml->type_operator == '+')
                    841:                value += (int64_t)ml->type_operand;
1.1       nicm      842:        else if (ml->type_operator != ' ')
                    843:                return (-1);
                    844:
                    845:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    846:        if (result == !ml->test_not && ml->result != NULL) {
                    847:                t = value;
                    848:                switch (ml->type) {
                    849:                case MAGIC_TYPE_QLDATE:
                    850:                case MAGIC_TYPE_LEQLDATE:
                    851:                case MAGIC_TYPE_BEQLDATE:
                    852:                        ctime_r(&t, s);
                    853:                        break;
                    854:                default:
1.6       nicm      855:                        asctime_r(gmtime(&t), s);
1.1       nicm      856:                        break;
                    857:                }
                    858:                s[strcspn(s, "\n")] = '\0';
                    859:                magic_add_result(ms, ml, "%s", s);
                    860:                ms->offset += sizeof value;
                    861:        }
                    862:        return (result);
                    863: }
                    864:
                    865: static int
                    866: magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
                    867: {
                    868:        uint32_t        value;
                    869:        int             result;
                    870:        time_t          t;
                    871:        char            s[64];
                    872:
                    873:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    874:                return (0);
1.22      nicm      875:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_BEDATE) ||
                    876:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_BELDATE))
1.3       brynet    877:                value = be32toh(value);
1.22      nicm      878:        if (ml->type == magic_reverse_type(ms, MAGIC_TYPE_LEDATE) ||
                    879:            ml->type == magic_reverse_type(ms, MAGIC_TYPE_LELDATE))
1.3       brynet    880:                value = le32toh(value);
1.1       nicm      881:
                    882:        if (ml->type_operator == '&')
                    883:                value &= (uint32_t)ml->type_operand;
1.13      nicm      884:        else if (ml->type_operator == '-')
                    885:                value -= (uint32_t)ml->type_operand;
                    886:        else if (ml->type_operator == '+')
                    887:                value += (uint32_t)ml->type_operand;
1.1       nicm      888:        else if (ml->type_operator != ' ')
                    889:                return (-1);
                    890:
                    891:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    892:        if (result == !ml->test_not && ml->result != NULL) {
                    893:                t = value;
                    894:                switch (ml->type) {
                    895:                case MAGIC_TYPE_LDATE:
                    896:                case MAGIC_TYPE_LELDATE:
                    897:                case MAGIC_TYPE_BELDATE:
                    898:                        ctime_r(&t, s);
                    899:                        break;
                    900:                default:
                    901:                        asctime_r(gmtime(&t), s);
                    902:                        break;
                    903:                }
                    904:                s[strcspn(s, "\n")] = '\0';
                    905:                magic_add_result(ms, ml, "%s", s);
                    906:                ms->offset += sizeof value;
                    907:        }
                    908:        return (result);
                    909: }
                    910:
                    911: static int
                    912: magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
                    913: {
                    914:        uint64_t        value;
                    915:        int             result;
                    916:        time_t          t;
                    917:        char            s[64];
                    918:
                    919:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    920:                return (0);
                    921:        if (ml->type == MAGIC_TYPE_UBEQDATE ||
                    922:            ml->type == MAGIC_TYPE_UBEQLDATE)
1.3       brynet    923:                value = be64toh(value);
1.1       nicm      924:        if (ml->type == MAGIC_TYPE_ULEQDATE ||
                    925:            ml->type == MAGIC_TYPE_ULEQLDATE)
1.3       brynet    926:                value = le64toh(value);
1.1       nicm      927:
                    928:        if (ml->type_operator == '&')
                    929:                value &= (uint64_t)ml->type_operand;
1.13      nicm      930:        else if (ml->type_operator == '-')
                    931:                value -= (uint64_t)ml->type_operand;
                    932:        else if (ml->type_operator == '+')
                    933:                value += (uint64_t)ml->type_operand;
1.1       nicm      934:        else if (ml->type_operator != ' ')
                    935:                return (-1);
                    936:
                    937:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    938:        if (result == !ml->test_not && ml->result != NULL) {
                    939:                t = value;
                    940:                switch (ml->type) {
                    941:                case MAGIC_TYPE_UQLDATE:
                    942:                case MAGIC_TYPE_ULEQLDATE:
                    943:                case MAGIC_TYPE_UBEQLDATE:
                    944:                        ctime_r(&t, s);
                    945:                        break;
                    946:                default:
                    947:                        asctime_r(gmtime(&t), s);
                    948:                        break;
                    949:                }
                    950:                s[strcspn(s, "\n")] = '\0';
                    951:                magic_add_result(ms, ml, "%s", s);
                    952:                ms->offset += sizeof value;
                    953:        }
                    954:        return (result);
                    955: }
                    956:
                    957: static int
                    958: magic_test_type_bestring16(__unused struct magic_line *ml,
                    959:     __unused struct magic_state *ms)
                    960: {
                    961:        return (-2);
                    962: }
                    963:
                    964: static int
                    965: magic_test_type_lestring16(__unused struct magic_line *ml,
                    966:     __unused struct magic_state *ms)
                    967: {
                    968:        return (-2);
                    969: }
                    970:
                    971: static int
                    972: magic_test_type_melong(__unused struct magic_line *ml,
                    973:     __unused struct magic_state *ms)
                    974: {
                    975:        return (-2);
                    976: }
                    977:
                    978: static int
                    979: magic_test_type_medate(__unused struct magic_line *ml,
                    980:     __unused struct magic_state *ms)
                    981: {
                    982:        return (-2);
                    983: }
                    984:
                    985: static int
                    986: magic_test_type_meldate(__unused struct magic_line *ml,
                    987:     __unused struct magic_state *ms)
                    988: {
                    989:        return (-2);
                    990: }
                    991:
                    992: static int
                    993: magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
                    994: {
                    995:        const char      *cp;
                    996:        regex_t          re;
                    997:        regmatch_t       m;
                    998:        int              result, flags = 0, sflag = 0;
                    999:
                   1000:        cp = &ml->type_string[(sizeof "regex") - 1];
                   1001:        if (*cp != '\0') {
                   1002:                if (*cp != '/')
                   1003:                        return (-1);
                   1004:                cp++;
                   1005:                for (; *cp != '\0'; cp++) {
                   1006:                        switch (*cp) {
                   1007:                        case 's':
                   1008:                                sflag = 1;
                   1009:                                break;
                   1010:                        case 'c':
                   1011:                                flags |= REG_ICASE;
                   1012:                                break;
                   1013:                        default:
                   1014:                                return (-1);
                   1015:                        }
                   1016:                }
                   1017:        }
                   1018:
                   1019:        if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
                   1020:                return (-1);
                   1021:        m.rm_so = ms->offset;
                   1022:        m.rm_eo = ms->size;
                   1023:
                   1024:        result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
1.12      nicm     1025:        if (result == !ml->test_not) {
1.17      nicm     1026:                if (ml->result != NULL) {
                   1027:                        magic_add_string(ms, ml, ms->base + m.rm_so,
                   1028:                            m.rm_eo - m.rm_so);
                   1029:                }
1.1       nicm     1030:                if (result) {
                   1031:                        if (sflag)
                   1032:                                ms->offset = m.rm_so;
                   1033:                        else
                   1034:                                ms->offset = m.rm_eo;
                   1035:                }
                   1036:        }
                   1037:        regfree(&re);
                   1038:        return (result);
                   1039: }
                   1040:
                   1041: static int
                   1042: magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
                   1043: {
                   1044:        const char      *cp, *endptr, *start, *found;
                   1045:        size_t           size, end, i;
                   1046:        uint64_t         range;
                   1047:        int              result, n, cflag = 0, bflag = 0, Bflag = 0;
                   1048:
                   1049:        cp = &ml->type_string[(sizeof "search") - 1];
                   1050:        if (*cp != '\0') {
                   1051:                if (*cp != '/')
                   1052:                        return (-1);
                   1053:                cp++;
                   1054:
                   1055:                endptr = magic_strtoull(cp, &range);
                   1056:                if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
                   1057:                        return (-1);
                   1058:
                   1059:                if (*endptr == '/') {
                   1060:                        for (cp = endptr + 1; *cp != '\0'; cp++) {
                   1061:                                switch (*cp) {
                   1062:                                case 'B':
1.11      nicm     1063:                                case 'W':
1.1       nicm     1064:                                        Bflag = 1;
                   1065:                                        break;
                   1066:                                case 'b':
1.11      nicm     1067:                                case 'w':
1.1       nicm     1068:                                        bflag = 1;
                   1069:                                        break;
                   1070:                                case 'c':
                   1071:                                        cflag = 1;
1.11      nicm     1072:                                        break;
                   1073:                                case 't':
1.1       nicm     1074:                                        break;
                   1075:                                default:
                   1076:                                        return (-1);
                   1077:                                }
                   1078:                        }
                   1079:                }
                   1080:        } else
                   1081:                range = UINT64_MAX;
                   1082:        if (range > (uint64_t)ms->size - ms->offset)
                   1083:                range = ms->size - ms->offset;
                   1084:        size = ml->test_string_size;
                   1085:
                   1086:        /* Want to search every starting position from up to range + size. */
                   1087:        end = range + size;
                   1088:        if (end > ms->size - ms->offset) {
                   1089:                if (size > ms->size - ms->offset)
                   1090:                        end = 0;
                   1091:                else
                   1092:                        end = ms->size - ms->offset - size;
                   1093:        }
                   1094:
                   1095:        /*
                   1096:         * < and > and the flags are only in /etc/magic with search/1 so don't
                   1097:         * support them with anything else.
                   1098:         */
                   1099:        start = ms->base + ms->offset;
                   1100:        if (end == 0)
                   1101:                found = NULL;
                   1102:        else if (ml->test_operator == 'x')
                   1103:                found = start;
                   1104:        else if (range == 1) {
                   1105:                n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
                   1106:                    size, cflag, bflag, Bflag);
                   1107:                if (n == -1 && ml->test_operator == '<')
                   1108:                        found = start;
                   1109:                else if (n == 1 && ml->test_operator == '>')
                   1110:                        found = start;
                   1111:                else if (n == 0 && ml->test_operator == '=')
                   1112:                        found = start;
                   1113:                else
                   1114:                        found = NULL;
                   1115:        } else {
                   1116:                if (ml->test_operator != '=')
                   1117:                        return (-2);
                   1118:                for (i = 0; i < end; i++) {
                   1119:                        n = magic_test_eq(start + i, ms->size - ms->offset - i,
                   1120:                            ml->test_string, size, cflag, bflag, Bflag);
                   1121:                        if (n == 0) {
                   1122:                                found = start + i;
                   1123:                                break;
                   1124:                        }
                   1125:                }
                   1126:                if (i == end)
                   1127:                        found = NULL;
                   1128:        }
                   1129:        result = (found != NULL);
                   1130:
1.12      nicm     1131:        if (result == !ml->test_not) {
                   1132:                if (ml->result != NULL)
                   1133:                        magic_add_string(ms, ml, found, ms->size - ms->offset);
                   1134:                if (result && found != NULL && ml->test_operator == '=')
                   1135:                        ms->offset = (found + size) - ms->base;
1.1       nicm     1136:        }
                   1137:        return (result);
                   1138: }
                   1139:
                   1140: static int
1.21      nicm     1141: magic_test_type_default(struct magic_line *ml, struct magic_state *ms)
1.1       nicm     1142: {
1.20      nicm     1143:        if (!ms->matched && ml->result != NULL)
                   1144:                magic_add_result(ms, ml, "%s", "");
1.18      nicm     1145:        return (!ms->matched);
1.1       nicm     1146: }
                   1147:
1.20      nicm     1148: static int
1.21      nicm     1149: magic_test_type_clear(struct magic_line *ml, struct magic_state *ms)
1.20      nicm     1150: {
                   1151:        if (ml->result != NULL)
                   1152:                magic_add_result(ms, ml, "%s", "");
                   1153:        return (1);
                   1154: }
                   1155:
1.22      nicm     1156: static int
                   1157: magic_test_type_name(__unused struct magic_line *ml,
                   1158:     __unused struct magic_state *ms)
                   1159: {
                   1160:        return (-1);
                   1161: }
                   1162:
                   1163: static int
                   1164: magic_test_type_use(__unused struct magic_line *ml,
                   1165:     __unused struct magic_state *ms)
                   1166: {
                   1167:        return (1);
                   1168: }
                   1169:
1.1       nicm     1170: static int (*magic_test_functions[])(struct magic_line *,
                   1171:     struct magic_state *) = {
                   1172:        magic_test_type_none,
                   1173:        magic_test_type_byte,
                   1174:        magic_test_type_short,
                   1175:        magic_test_type_long,
                   1176:        magic_test_type_quad,
                   1177:        magic_test_type_ubyte,
                   1178:        magic_test_type_ushort,
                   1179:        magic_test_type_ulong,
                   1180:        magic_test_type_uquad,
                   1181:        magic_test_type_float,
                   1182:        magic_test_type_double,
                   1183:        magic_test_type_string,
                   1184:        magic_test_type_pstring,
                   1185:        magic_test_type_date,
                   1186:        magic_test_type_qdate,
                   1187:        magic_test_type_date,
                   1188:        magic_test_type_qdate,
                   1189:        magic_test_type_udate,
                   1190:        magic_test_type_uqdate,
                   1191:        magic_test_type_udate,
                   1192:        magic_test_type_qdate,
                   1193:        magic_test_type_short,
                   1194:        magic_test_type_long,
                   1195:        magic_test_type_quad,
                   1196:        magic_test_type_ushort,
                   1197:        magic_test_type_ulong,
                   1198:        magic_test_type_uquad,
                   1199:        magic_test_type_float,
                   1200:        magic_test_type_double,
                   1201:        magic_test_type_date,
                   1202:        magic_test_type_qdate,
                   1203:        magic_test_type_date,
                   1204:        magic_test_type_qdate,
                   1205:        magic_test_type_udate,
                   1206:        magic_test_type_uqdate,
                   1207:        magic_test_type_udate,
                   1208:        magic_test_type_uqdate,
                   1209:        magic_test_type_bestring16,
                   1210:        magic_test_type_short,
                   1211:        magic_test_type_long,
                   1212:        magic_test_type_quad,
                   1213:        magic_test_type_ushort,
                   1214:        magic_test_type_ulong,
                   1215:        magic_test_type_uquad,
                   1216:        magic_test_type_float,
                   1217:        magic_test_type_double,
                   1218:        magic_test_type_date,
                   1219:        magic_test_type_qdate,
                   1220:        magic_test_type_date,
                   1221:        magic_test_type_qdate,
                   1222:        magic_test_type_udate,
                   1223:        magic_test_type_uqdate,
                   1224:        magic_test_type_udate,
                   1225:        magic_test_type_uqdate,
                   1226:        magic_test_type_lestring16,
                   1227:        magic_test_type_melong,
                   1228:        magic_test_type_medate,
                   1229:        magic_test_type_meldate,
                   1230:        magic_test_type_regex,
                   1231:        magic_test_type_search,
                   1232:        magic_test_type_default,
1.20      nicm     1233:        magic_test_type_clear,
1.22      nicm     1234:        magic_test_type_name,
                   1235:        magic_test_type_use,
1.1       nicm     1236: };
                   1237:
1.22      nicm     1238: static void
                   1239: magic_test_children(struct magic_line *ml, struct magic_state *ms, size_t start,
                   1240:     int reverse)
                   1241: {
                   1242:        struct magic_line       *child;
                   1243:        size_t                   saved_start, saved_offset;
                   1244:        int                      saved_reverse;
                   1245:
                   1246:        saved_start = ms->start;
                   1247:        saved_reverse = ms->reverse;
                   1248:        saved_offset = ms->offset;
                   1249:
                   1250:        ms->matched = 0; /* no need to save, caller will set too */
                   1251:
                   1252:        TAILQ_FOREACH(child, &ml->children, entry) {
                   1253:                ms->start = start;
                   1254:                ms->reverse = reverse;
                   1255:                ms->offset = saved_offset;
                   1256:
                   1257:                magic_test_line(child, ms);
                   1258:        }
                   1259:
                   1260:        ms->start = saved_start;
                   1261:        ms->reverse = saved_reverse;
                   1262:        ms->offset = saved_offset;
                   1263: }
                   1264:
1.1       nicm     1265: static int
                   1266: magic_test_line(struct magic_line *ml, struct magic_state *ms)
                   1267: {
1.22      nicm     1268:        struct magic            *m = ml->root;
                   1269:        struct magic_line       *named;
1.1       nicm     1270:        int64_t                  offset, wanted, next;
                   1271:        int                      result;
                   1272:        uint8_t                  b;
                   1273:        uint16_t                 s;
                   1274:        uint32_t                 l;
                   1275:
                   1276:        if (ml->indirect_type == ' ')
1.22      nicm     1277:                wanted = ms->start + ml->offset;
1.1       nicm     1278:        else {
                   1279:                wanted = ml->indirect_offset;
                   1280:                if (ml->indirect_relative) {
1.14      nicm     1281:                        if (wanted < 0 && (size_t)-wanted > ms->offset)
1.1       nicm     1282:                                return (0);
                   1283:                        if (wanted > 0 && ms->offset + wanted > ms->size)
                   1284:                                return (0);
                   1285:                        next = ms->offset + ml->indirect_offset;
                   1286:                } else
                   1287:                        next = wanted;
                   1288:
                   1289:                switch (ml->indirect_type) {
                   1290:                case 'b':
                   1291:                case 'B':
                   1292:                        if (magic_copy_from(ms, next, &b, sizeof b) != 0)
                   1293:                                return (0);
                   1294:                        wanted = b;
                   1295:                        break;
                   1296:                case 's':
                   1297:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1298:                                return (0);
1.3       brynet   1299:                        wanted = le16toh(s);
1.1       nicm     1300:                        break;
                   1301:                case 'S':
                   1302:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1303:                                return (0);
1.3       brynet   1304:                        wanted = be16toh(s);
1.1       nicm     1305:                        break;
                   1306:                case 'l':
                   1307:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1308:                                return (0);
1.3       brynet   1309:                        wanted = le16toh(l);
1.1       nicm     1310:                        break;
                   1311:                case 'L':
                   1312:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1313:                                return (0);
1.3       brynet   1314:                        wanted = be16toh(l);
1.1       nicm     1315:                        break;
                   1316:                }
                   1317:
                   1318:                switch (ml->indirect_operator) {
                   1319:                case '+':
                   1320:                        wanted += ml->indirect_operand;
                   1321:                        break;
                   1322:                case '-':
                   1323:                        wanted -= ml->indirect_operand;
                   1324:                        break;
                   1325:                case '*':
                   1326:                        wanted *= ml->indirect_operand;
                   1327:                        break;
                   1328:                }
                   1329:        }
                   1330:
                   1331:        if (ml->offset_relative) {
1.14      nicm     1332:                if (wanted < 0 && (size_t)-wanted > ms->offset)
1.1       nicm     1333:                        return (0);
                   1334:                if (wanted > 0 && ms->offset + wanted > ms->size)
                   1335:                        return (0);
                   1336:                offset = ms->offset + wanted;
                   1337:        } else
                   1338:                offset = wanted;
1.14      nicm     1339:        if (offset < 0 || (size_t)offset > ms->size)
1.1       nicm     1340:                return (0);
1.22      nicm     1341:        ms->offset = offset; /* test function may update */
1.1       nicm     1342:
                   1343:        result = magic_test_functions[ml->type](ml, ms);
                   1344:        if (result == -1) {
                   1345:                magic_warn(ml, "test %s/%c failed", ml->type_string,
                   1346:                    ml->test_operator);
                   1347:                return (0);
                   1348:        }
                   1349:        if (result == -2) {
                   1350:                magic_warn(ml, "test %s/%c not implemented", ml->type_string,
                   1351:                    ml->test_operator);
                   1352:                return (0);
                   1353:        }
                   1354:        if (result == ml->test_not)
                   1355:                return (0);
                   1356:        if (ml->mimetype != NULL)
                   1357:                ms->mimetype = ml->mimetype;
                   1358:
1.22      nicm     1359:        magic_warn(ml, "test %s/%c matched at offset %lld (now %zu): "
                   1360:            "'%s'", ml->type_string, ml->test_operator, offset,
                   1361:            ms->offset, ml->result == NULL ? "" : ml->result);
                   1362:
                   1363:        if (ml->type == MAGIC_TYPE_USE) {
                   1364:                if (*ml->name == '^')
                   1365:                        named = magic_get_named(m, ml->name + 1);
                   1366:                else
                   1367:                        named = magic_get_named(m, ml->name);
                   1368:                if (named == NULL) {
                   1369:                        magic_warn(ml, "no name found for use %s", ml->name);
                   1370:                        return (0);
                   1371:                }
                   1372:                magic_warn(ml, "use %s at offset %lld", ml->name, offset);
                   1373:                magic_test_children(named, ms, offset, *ml->name == '^');
                   1374:        }
1.1       nicm     1375:
1.22      nicm     1376:        magic_test_children(ml, ms, ms->start, ms->reverse);
1.18      nicm     1377:
1.20      nicm     1378:        if (ml->type == MAGIC_TYPE_CLEAR)
                   1379:                ms->matched = 0;
                   1380:        else
                   1381:                ms->matched = 1;
1.5       nicm     1382:        return (ml->result != NULL);
1.1       nicm     1383: }
                   1384:
                   1385: const char *
                   1386: magic_test(struct magic *m, const void *base, size_t size, int flags)
                   1387: {
                   1388:        struct magic_line               *ml;
                   1389:        static struct magic_state        ms;
                   1390:
                   1391:        memset(&ms, 0, sizeof ms);
                   1392:
                   1393:        ms.base = base;
                   1394:        ms.size = size;
                   1395:
                   1396:        ms.text = !!(flags & MAGIC_TEST_TEXT);
                   1397:
                   1398:        RB_FOREACH(ml, magic_tree, &m->tree) {
                   1399:                ms.offset = 0;
                   1400:                if (ml->text == ms.text && magic_test_line(ml, &ms))
                   1401:                        break;
                   1402:        }
                   1403:
                   1404:        if (*ms.out != '\0') {
                   1405:                if (flags & MAGIC_TEST_MIME) {
1.25    ! nicm     1406:                        if (ms.mimetype != NULL)
1.1       nicm     1407:                                return (xstrdup(ms.mimetype));
                   1408:                        return (NULL);
                   1409:                }
                   1410:                return (xstrdup(ms.out));
                   1411:        }
                   1412:        return (NULL);
                   1413: }