[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.5

1.5     ! nicm        1: /* $OpenBSD: magic-test.c,v 1.4 2015/05/29 14:52:10 nicm 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>
                     30: #include <unistd.h>
                     31: #include <vis.h>
                     32:
                     33: #include "magic.h"
                     34: #include "xmalloc.h"
                     35:
                     36: static int
                     37: magic_one_eq(char a, char b, int cflag)
                     38: {
                     39:        if (a == b)
                     40:                return (1);
1.4       nicm       41:        if (cflag && islower((u_char)b) && tolower((u_char)a) == (u_char)b)
1.1       nicm       42:                return (1);
                     43:        return (0);
                     44: }
                     45:
                     46: static int
                     47: magic_test_eq(const char *ap, size_t asize, const char *bp, size_t bsize,
                     48:     int cflag, int bflag, int Bflag)
                     49: {
                     50:        size_t  aoff, boff, aspaces, bspaces;
                     51:
                     52:        aoff = boff = 0;
                     53:        while (aoff != asize && boff != bsize) {
                     54:                if (Bflag && isspace((u_char)ap[aoff])) {
                     55:                        aspaces = 0;
                     56:                        while (aoff != asize && isspace((u_char)ap[aoff])) {
                     57:                                aspaces++;
                     58:                                aoff++;
                     59:                        }
                     60:                        bspaces = 0;
                     61:                        while (boff != bsize && isspace((u_char)bp[boff])) {
                     62:                                bspaces++;
                     63:                                boff++;
                     64:                        }
                     65:                        if (bspaces >= aspaces)
                     66:                                continue;
                     67:                        return (1);
                     68:                }
                     69:                if (magic_one_eq(ap[aoff], bp[boff], cflag)) {
                     70:                        aoff++;
                     71:                        boff++;
                     72:                        continue;
                     73:                }
                     74:                if (bflag && isspace((u_char)bp[boff])) {
                     75:                        boff++;
                     76:                        continue;
                     77:                }
                     78:                if (ap[aoff] < bp[boff])
                     79:                        return (-1);
                     80:                return (1);
                     81:        }
                     82:        return (0);
                     83: }
                     84:
                     85: static int
                     86: magic_copy_from(struct magic_state *ms, ssize_t offset, void *dst, size_t size)
                     87: {
                     88:        if (offset < 0)
                     89:                offset = ms->offset;
                     90:        if (offset + size > ms->size)
                     91:                return (-1);
                     92:        memcpy(dst, ms->base + offset, size);
                     93:        return (0);
                     94: }
                     95:
                     96: static void
                     97: magic_add_result(struct magic_state *ms, struct magic_line *ml,
                     98:     const char *fmt, ...)
                     99: {
                    100:        va_list  ap;
                    101:        int      separate;
                    102:        char    *s, *tmp, *add;
                    103:
                    104:        va_start(ap, fmt);
                    105:        if (ml->stringify) {
                    106:                if (vasprintf(&s, fmt, ap) == -1) {
                    107:                        va_end(ap);
                    108:                        return;
                    109:                }
                    110:                va_end(ap);
                    111:                if (asprintf(&tmp, ml->result, s) == -1) {
                    112:                        free(s);
                    113:                        return;
                    114:                }
                    115:                free(s);
                    116:        } else {
                    117:                if (vasprintf(&tmp, ml->result, ap) == -1) {
                    118:                        va_end(ap);
                    119:                        return;
                    120:                }
                    121:                va_end(ap);
                    122:        }
                    123:
                    124:        separate = 1;
                    125:        if (tmp[0] == '\\' && tmp[1] == 'b') {
                    126:                separate = 0;
                    127:                add = tmp + 2;
                    128:        } else
                    129:                add = tmp;
                    130:
                    131:        if (separate && *ms->out != '\0')
                    132:                strlcat(ms->out, " ", sizeof ms->out);
                    133:        strlcat(ms->out, add, sizeof ms->out);
                    134:
                    135:        free(tmp);
                    136: }
                    137:
                    138: static void
                    139: magic_add_string(struct magic_state *ms, struct magic_line *ml,
1.2       deraadt   140:     const char *s, size_t slen)
1.1       nicm      141: {
                    142:        char    *out;
                    143:        size_t   outlen, offset;
                    144:
                    145:        outlen = MAGIC_STRING_SIZE;
                    146:        if (outlen > slen)
                    147:                outlen = slen;
                    148:        for (offset = 0; offset < outlen; offset++) {
                    149:                if (s[offset] == '\0' || !isprint((u_char)s[offset])) {
                    150:                        outlen = offset;
                    151:                        break;
                    152:                }
                    153:        }
                    154:        out = xreallocarray(NULL, 4, outlen + 1);
                    155:        strvisx(out, s, outlen, VIS_TAB|VIS_NL|VIS_CSTYLE|VIS_OCTAL);
                    156:        magic_add_result(ms, ml, "%s", out);
                    157:        free(out);
                    158: }
                    159:
                    160: static int
                    161: magic_test_signed(struct magic_line *ml, int64_t value, int64_t wanted)
                    162: {
                    163:        switch (ml->test_operator) {
                    164:        case 'x':
                    165:                return (1);
                    166:        case '<':
                    167:                return (value < wanted);
                    168:        case '[':
                    169:                return (value <= wanted);
                    170:        case '>':
                    171:                return (value > wanted);
                    172:        case ']':
                    173:                return (value >= wanted);
                    174:        case '=':
                    175:                return (value == wanted);
                    176:        case '&':
                    177:                return ((value & wanted) == wanted);
                    178:        case '^':
                    179:                return ((~value & wanted) == wanted);
                    180:        }
                    181:        return (-1);
                    182: }
                    183:
                    184: static int
                    185: magic_test_unsigned(struct magic_line *ml, uint64_t value, uint64_t wanted)
                    186: {
                    187:        switch (ml->test_operator) {
                    188:        case 'x':
                    189:                return (1);
                    190:        case '<':
                    191:                return (value < wanted);
                    192:        case '[':
                    193:                return (value <= wanted);
                    194:        case '>':
                    195:                return (value > wanted);
                    196:        case ']':
                    197:                return (value >= wanted);
                    198:        case '=':
                    199:                return (value == wanted);
                    200:        case '&':
                    201:                return ((value & wanted) == wanted);
                    202:        case '^':
                    203:                return ((~value & wanted) == wanted);
                    204:        }
                    205:        return (-1);
                    206: }
                    207:
                    208: static int
                    209: magic_test_type_none(__unused struct magic_line *ml,
                    210:     __unused struct magic_state *ms)
                    211: {
                    212:        return (0);
                    213: }
                    214:
                    215: static int
                    216: magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
                    217: {
                    218:        int8_t  value;
                    219:        int     result;
                    220:
                    221:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    222:                return (0);
                    223:
                    224:        if (ml->type_operator == '&')
                    225:                value &= (int8_t)ml->type_operand;
                    226:        else if (ml->type_operator != ' ')
                    227:                return (-1);
                    228:
                    229:        result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
                    230:        if (result == !ml->test_not && ml->result != NULL) {
                    231:                magic_add_result(ms, ml, "%c", (int)value);
                    232:                ms->offset += sizeof value;
                    233:        }
                    234:        return (result);
                    235: }
                    236:
                    237: static int
                    238: magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
                    239: {
                    240:        int16_t value;
                    241:        int     result;
                    242:
                    243:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    244:                return (0);
                    245:        if (ml->type == MAGIC_TYPE_BESHORT)
1.3       brynet    246:                value = be16toh(value);
1.1       nicm      247:        if (ml->type == MAGIC_TYPE_LESHORT)
1.3       brynet    248:                value = le16toh(value);
1.1       nicm      249:
                    250:        if (ml->type_operator == '&')
                    251:                value &= (int16_t)ml->type_operand;
                    252:        else if (ml->type_operator != ' ')
                    253:                return (-1);
                    254:
                    255:        result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
                    256:        if (result == !ml->test_not && ml->result != NULL) {
                    257:                magic_add_result(ms, ml, "%hd", (int)value);
                    258:                ms->offset += sizeof value;
                    259:        }
                    260:        return (result);
                    261: }
                    262:
                    263: static int
                    264: magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
                    265: {
                    266:        int32_t value;
                    267:        int     result;
                    268:
                    269:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    270:                return (0);
                    271:        if (ml->type == MAGIC_TYPE_BELONG)
1.3       brynet    272:                value = be32toh(value);
1.1       nicm      273:        if (ml->type == MAGIC_TYPE_LELONG)
1.3       brynet    274:                value = le32toh(value);
1.1       nicm      275:
                    276:        if (ml->type_operator == '&')
                    277:                value &= (int32_t)ml->type_operand;
                    278:        else if (ml->type_operator != ' ')
                    279:                return (-1);
                    280:
                    281:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    282:        if (result == !ml->test_not && ml->result != NULL) {
                    283:                magic_add_result(ms, ml, "%d", (int)value);
                    284:                ms->offset += sizeof value;
                    285:        }
                    286:        return (result);
                    287: }
                    288:
                    289: static int
                    290: magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
                    291: {
                    292:        int64_t value;
                    293:        int     result;
                    294:
                    295:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    296:                return (0);
                    297:        if (ml->type == MAGIC_TYPE_BEQUAD)
1.3       brynet    298:                value = be64toh(value);
1.1       nicm      299:        if (ml->type == MAGIC_TYPE_LEQUAD)
1.3       brynet    300:                value = le64toh(value);
1.1       nicm      301:
                    302:        if (ml->type_operator == '&')
                    303:                value &= (int64_t)ml->type_operand;
                    304:        else if (ml->type_operator != ' ')
                    305:                return (-1);
                    306:
                    307:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    308:        if (result == !ml->test_not && ml->result != NULL) {
                    309:                magic_add_result(ms, ml, "%lld", (long long)value);
                    310:                ms->offset += sizeof value;
                    311:        }
                    312:        return (result);
                    313: }
                    314:
                    315: static int
                    316: magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
                    317: {
                    318:        uint8_t value;
                    319:        int     result;
                    320:
                    321:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    322:                return (0);
                    323:
                    324:        if (ml->type_operator == '&')
                    325:                value &= (uint8_t)ml->type_operand;
                    326:        else if (ml->type_operator != ' ')
                    327:                return (-1);
                    328:
                    329:        result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
                    330:        if (result == !ml->test_not && ml->result != NULL) {
                    331:                magic_add_result(ms, ml, "%c", (unsigned int)value);
                    332:                ms->offset += sizeof value;
                    333:        }
                    334:        return (result);
                    335: }
                    336:
                    337: static int
                    338: magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
                    339: {
                    340:        uint16_t        value;
                    341:        int             result;
                    342:
                    343:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    344:                return (0);
                    345:        if (ml->type == MAGIC_TYPE_UBESHORT)
1.3       brynet    346:                value = be16toh(value);
1.1       nicm      347:        if (ml->type == MAGIC_TYPE_ULESHORT)
1.3       brynet    348:                value = le16toh(value);
1.1       nicm      349:
                    350:        if (ml->type_operator == '&')
                    351:                value &= (uint16_t)ml->type_operand;
                    352:        else if (ml->type_operator != ' ')
                    353:                return (-1);
                    354:
                    355:        result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
                    356:        if (result == !ml->test_not && ml->result != NULL) {
                    357:                magic_add_result(ms, ml, "%hu", (unsigned int)value);
                    358:                ms->offset += sizeof value;
                    359:        }
                    360:        return (result);
                    361: }
                    362:
                    363: static int
                    364: magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
                    365: {
                    366:        uint32_t        value;
                    367:        int             result;
                    368:
                    369:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    370:                return (0);
                    371:        if (ml->type == MAGIC_TYPE_UBELONG)
1.3       brynet    372:                value = be32toh(value);
1.1       nicm      373:        if (ml->type == MAGIC_TYPE_ULELONG)
1.3       brynet    374:                value = le32toh(value);
1.1       nicm      375:
                    376:        if (ml->type_operator == '&')
                    377:                value &= (uint32_t)ml->type_operand;
                    378:        else if (ml->type_operator != ' ')
                    379:                return (-1);
                    380:
                    381:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    382:        if (result == !ml->test_not && ml->result != NULL) {
                    383:                magic_add_result(ms, ml, "%u", (unsigned int)value);
                    384:                ms->offset += sizeof value;
                    385:        }
                    386:        return (result);
                    387: }
                    388:
                    389: static int
                    390: magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
                    391: {
                    392:        uint64_t        value;
                    393:        int             result;
                    394:
                    395:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    396:                return (0);
                    397:        if (ml->type == MAGIC_TYPE_UBEQUAD)
1.3       brynet    398:                value = be64toh(value);
1.1       nicm      399:        if (ml->type == MAGIC_TYPE_ULEQUAD)
1.3       brynet    400:                value = le64toh(value);
1.1       nicm      401:
                    402:        if (ml->type_operator == '&')
                    403:                value &= (uint64_t)ml->type_operand;
                    404:        else if (ml->type_operator != ' ')
                    405:                return (-1);
                    406:
                    407:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    408:        if (result == !ml->test_not && ml->result != NULL) {
                    409:                magic_add_result(ms, ml, "%llu", (unsigned long long)value);
                    410:                ms->offset += sizeof value;
                    411:        }
                    412:        return (result);
                    413: }
                    414:
                    415: static int
                    416: magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
                    417: {
                    418:        uint32_t        value0;
                    419:        double          value;
                    420:
                    421:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    422:                return (0);
                    423:        if (ml->type == MAGIC_TYPE_BEFLOAT)
1.3       brynet    424:                value0 = be32toh(value0);
1.1       nicm      425:        if (ml->type == MAGIC_TYPE_LEFLOAT)
1.3       brynet    426:                value0 = le32toh(value0);
1.1       nicm      427:        memcpy(&value, &value0, sizeof value);
                    428:
                    429:        if (ml->type_operator != ' ')
                    430:                return (-1);
                    431:
                    432:        if (ml->test_operator != 'x')
                    433:                return (-1);
                    434:
                    435:        magic_add_result(ms, ml, "%g", value);
                    436:        ms->offset += sizeof value0;
                    437:        return (1);
                    438: }
                    439:
                    440: static int
                    441: magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
                    442: {
                    443:        uint64_t        value0;
                    444:        double          value;
                    445:
                    446:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    447:                return (0);
                    448:        if (ml->type == MAGIC_TYPE_BEDOUBLE)
1.3       brynet    449:                value0 = be64toh(value0);
1.1       nicm      450:        if (ml->type == MAGIC_TYPE_LEDOUBLE)
1.3       brynet    451:                value0 = le64toh(value0);
1.1       nicm      452:        memcpy(&value, &value0, sizeof value);
                    453:
                    454:        if (ml->type_operator != ' ')
                    455:                return (-1);
                    456:
                    457:        if (ml->test_operator != 'x')
                    458:                return (-1);
                    459:
                    460:        magic_add_result(ms, ml, "%g", value);
                    461:        ms->offset += sizeof value0;
                    462:        return (1);
                    463: }
                    464:
                    465: static int
                    466: magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
                    467: {
                    468:        const char      *s, *cp;
                    469:        size_t           slen;
                    470:        int              result, cflag = 0, bflag = 0, Bflag = 0;
                    471:
                    472:        cp = &ml->type_string[(sizeof "string") - 1];
                    473:        if (*cp != '\0') {
                    474:                if (*cp != '/')
                    475:                        return (-1);
                    476:                cp++;
                    477:                for (; *cp != '\0'; cp++) {
                    478:                        switch (*cp) {
                    479:                        case 'B':
                    480:                                Bflag = 1;
                    481:                                break;
                    482:                        case 'b':
                    483:                                bflag = 1;
                    484:                                break;
                    485:                        case 'c':
                    486:                                cflag = 1;
                    487:                                break;
                    488:                        default:
                    489:                                return (-1);
                    490:                        }
                    491:                }
                    492:        }
                    493:
                    494:        s = ms->base + ms->offset;
                    495:        slen = ms->size - ms->offset;
                    496:        if (slen < ml->test_string_size)
                    497:                return (0);
                    498:
                    499:        result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
                    500:            cflag, bflag, Bflag);
                    501:        switch (ml->test_operator) {
                    502:        case 'x':
                    503:                result = 1;
                    504:                break;
                    505:        case '<':
                    506:                result = result < 0;
                    507:                break;
                    508:        case '>':
                    509:                result = result > 0;
                    510:                break;
                    511:        case '=':
                    512:                result = result == 0;
                    513:                break;
                    514:        default:
                    515:                result = -1;
                    516:                break;
                    517:        }
                    518:        if (result == !ml->test_not) {
                    519:                if (ml->result != NULL)
                    520:                        magic_add_string(ms, ml, s, slen);
                    521:                if (result && ml->test_operator == '=')
                    522:                        ms->offset = s - ms->base + ml->test_string_size;
                    523:        }
                    524:        return (result);
                    525: }
                    526:
                    527: static int
                    528: magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
                    529: {
                    530:        const char      *s;
                    531:        size_t           slen;
                    532:        int              result;
                    533:
                    534:        s = ms->base + ms->offset;
                    535:        if (ms->size - ms->offset < 1)
                    536:                return (-1);
                    537:        slen = *(u_char *)s;
                    538:        if (slen > ms->size - ms->offset)
                    539:                return (-1);
                    540:        s++;
                    541:
                    542:        if (slen < ml->test_string_size)
                    543:                result = -1;
                    544:        else if (slen > ml->test_string_size)
                    545:                result = 1;
                    546:        else
                    547:                result = memcmp(s, ml->test_string, ml->test_string_size);
                    548:        switch (ml->test_operator) {
                    549:        case 'x':
                    550:                result = 1;
                    551:                break;
                    552:        case '<':
                    553:                result = result < 0;
                    554:                break;
                    555:        case '>':
                    556:                result = result > 0;
                    557:                break;
                    558:        case '=':
                    559:                result = result == 0;
                    560:                break;
                    561:        default:
                    562:                result = -1;
                    563:                break;
                    564:        }
                    565:        if (result == !ml->test_not) {
                    566:                if (ml->result != NULL)
                    567:                        magic_add_string(ms, ml, s, slen);
                    568:                if (result)
                    569:                        ms->offset += slen + 1;
                    570:        }
                    571:        return (result);
                    572: }
                    573:
                    574: static int
                    575: magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
                    576: {
                    577:        int32_t value;
                    578:        int     result;
                    579:        time_t  t;
                    580:        char    s[64];
                    581:
                    582:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    583:                return (0);
                    584:        if (ml->type == MAGIC_TYPE_BEDATE ||
                    585:            ml->type == MAGIC_TYPE_BELDATE)
1.3       brynet    586:                value = be32toh(value);
1.1       nicm      587:        if (ml->type == MAGIC_TYPE_LEDATE ||
                    588:            ml->type == MAGIC_TYPE_LELDATE)
1.3       brynet    589:                value = le32toh(value);
1.1       nicm      590:
                    591:        if (ml->type_operator == '&')
                    592:                value &= (int32_t)ml->type_operand;
                    593:        else if (ml->type_operator != ' ')
                    594:                return (-1);
                    595:
                    596:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    597:        if (result == !ml->test_not && ml->result != NULL) {
                    598:                t = value;
                    599:                switch (ml->type) {
                    600:                case MAGIC_TYPE_LDATE:
                    601:                case MAGIC_TYPE_LELDATE:
                    602:                case MAGIC_TYPE_BELDATE:
                    603:                        ctime_r(&t, s);
                    604:                        break;
                    605:                default:
                    606:                        asctime_r(localtime(&t), s);
                    607:                        break;
                    608:                }
                    609:                s[strcspn(s, "\n")] = '\0';
                    610:                magic_add_result(ms, ml, "%s", s);
                    611:                ms->offset += sizeof value;
                    612:        }
                    613:        return (result);
                    614: }
                    615:
                    616: static int
                    617: magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
                    618: {
                    619:        int64_t value;
                    620:        int     result;
                    621:        time_t  t;
                    622:        char    s[64];
                    623:
                    624:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    625:                return (0);
                    626:        if (ml->type == MAGIC_TYPE_BEQDATE ||
                    627:            ml->type == MAGIC_TYPE_BEQLDATE)
1.3       brynet    628:                value = be64toh(value);
1.1       nicm      629:        if (ml->type == MAGIC_TYPE_LEQDATE ||
                    630:            ml->type == MAGIC_TYPE_LEQLDATE)
1.3       brynet    631:                value = le64toh(value);
1.1       nicm      632:
                    633:        if (ml->type_operator == '&')
                    634:                value &= (int64_t)ml->type_operand;
                    635:        else if (ml->type_operator != ' ')
                    636:                return (-1);
                    637:
                    638:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    639:        if (result == !ml->test_not && ml->result != NULL) {
                    640:                t = value;
                    641:                switch (ml->type) {
                    642:                case MAGIC_TYPE_QLDATE:
                    643:                case MAGIC_TYPE_LEQLDATE:
                    644:                case MAGIC_TYPE_BEQLDATE:
                    645:                        ctime_r(&t, s);
                    646:                        break;
                    647:                default:
                    648:                        asctime_r(localtime(&t), s);
                    649:                        break;
                    650:                }
                    651:                s[strcspn(s, "\n")] = '\0';
                    652:                magic_add_result(ms, ml, "%s", s);
                    653:                ms->offset += sizeof value;
                    654:        }
                    655:        return (result);
                    656: }
                    657:
                    658: static int
                    659: magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
                    660: {
                    661:        uint32_t        value;
                    662:        int             result;
                    663:        time_t          t;
                    664:        char            s[64];
                    665:
                    666:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    667:                return (0);
                    668:        if (ml->type == MAGIC_TYPE_BEDATE ||
                    669:            ml->type == MAGIC_TYPE_BELDATE)
1.3       brynet    670:                value = be32toh(value);
1.1       nicm      671:        if (ml->type == MAGIC_TYPE_LEDATE ||
                    672:            ml->type == MAGIC_TYPE_LELDATE)
1.3       brynet    673:                value = le32toh(value);
1.1       nicm      674:
                    675:        if (ml->type_operator == '&')
                    676:                value &= (uint32_t)ml->type_operand;
                    677:        else if (ml->type_operator != ' ')
                    678:                return (-1);
                    679:
                    680:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    681:        if (result == !ml->test_not && ml->result != NULL) {
                    682:                t = value;
                    683:                switch (ml->type) {
                    684:                case MAGIC_TYPE_LDATE:
                    685:                case MAGIC_TYPE_LELDATE:
                    686:                case MAGIC_TYPE_BELDATE:
                    687:                        ctime_r(&t, s);
                    688:                        break;
                    689:                default:
                    690:                        asctime_r(gmtime(&t), s);
                    691:                        break;
                    692:                }
                    693:                s[strcspn(s, "\n")] = '\0';
                    694:                magic_add_result(ms, ml, "%s", s);
                    695:                ms->offset += sizeof value;
                    696:        }
                    697:        return (result);
                    698: }
                    699:
                    700: static int
                    701: magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
                    702: {
                    703:        uint64_t        value;
                    704:        int             result;
                    705:        time_t          t;
                    706:        char            s[64];
                    707:
                    708:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    709:                return (0);
                    710:        if (ml->type == MAGIC_TYPE_UBEQDATE ||
                    711:            ml->type == MAGIC_TYPE_UBEQLDATE)
1.3       brynet    712:                value = be64toh(value);
1.1       nicm      713:        if (ml->type == MAGIC_TYPE_ULEQDATE ||
                    714:            ml->type == MAGIC_TYPE_ULEQLDATE)
1.3       brynet    715:                value = le64toh(value);
1.1       nicm      716:
                    717:        if (ml->type_operator == '&')
                    718:                value &= (uint64_t)ml->type_operand;
                    719:        else if (ml->type_operator != ' ')
                    720:                return (-1);
                    721:
                    722:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    723:        if (result == !ml->test_not && ml->result != NULL) {
                    724:                t = value;
                    725:                switch (ml->type) {
                    726:                case MAGIC_TYPE_UQLDATE:
                    727:                case MAGIC_TYPE_ULEQLDATE:
                    728:                case MAGIC_TYPE_UBEQLDATE:
                    729:                        ctime_r(&t, s);
                    730:                        break;
                    731:                default:
                    732:                        asctime_r(gmtime(&t), s);
                    733:                        break;
                    734:                }
                    735:                s[strcspn(s, "\n")] = '\0';
                    736:                magic_add_result(ms, ml, "%s", s);
                    737:                ms->offset += sizeof value;
                    738:        }
                    739:        return (result);
                    740: }
                    741:
                    742: static int
                    743: magic_test_type_bestring16(__unused struct magic_line *ml,
                    744:     __unused struct magic_state *ms)
                    745: {
                    746:        return (-2);
                    747: }
                    748:
                    749: static int
                    750: magic_test_type_lestring16(__unused struct magic_line *ml,
                    751:     __unused struct magic_state *ms)
                    752: {
                    753:        return (-2);
                    754: }
                    755:
                    756: static int
                    757: magic_test_type_melong(__unused struct magic_line *ml,
                    758:     __unused struct magic_state *ms)
                    759: {
                    760:        return (-2);
                    761: }
                    762:
                    763: static int
                    764: magic_test_type_medate(__unused struct magic_line *ml,
                    765:     __unused struct magic_state *ms)
                    766: {
                    767:        return (-2);
                    768: }
                    769:
                    770: static int
                    771: magic_test_type_meldate(__unused struct magic_line *ml,
                    772:     __unused struct magic_state *ms)
                    773: {
                    774:        return (-2);
                    775: }
                    776:
                    777: static int
                    778: magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
                    779: {
                    780:        const char      *cp;
                    781:        regex_t          re;
                    782:        regmatch_t       m;
                    783:        int              result, flags = 0, sflag = 0;
                    784:
                    785:        cp = &ml->type_string[(sizeof "regex") - 1];
                    786:        if (*cp != '\0') {
                    787:                if (*cp != '/')
                    788:                        return (-1);
                    789:                cp++;
                    790:                for (; *cp != '\0'; cp++) {
                    791:                        switch (*cp) {
                    792:                        case 's':
                    793:                                sflag = 1;
                    794:                                break;
                    795:                        case 'c':
                    796:                                flags |= REG_ICASE;
                    797:                                break;
                    798:                        default:
                    799:                                return (-1);
                    800:                        }
                    801:                }
                    802:        }
                    803:
                    804:        if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
                    805:                return (-1);
                    806:        m.rm_so = ms->offset;
                    807:        m.rm_eo = ms->size;
                    808:
                    809:        result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
                    810:        if (result == !ml->test_not && ml->result != NULL) {
                    811:                magic_add_result(ms, ml, "%s", "");
                    812:                if (result) {
                    813:                        if (sflag)
                    814:                                ms->offset = m.rm_so;
                    815:                        else
                    816:                                ms->offset = m.rm_eo;
                    817:                }
                    818:        }
                    819:        regfree(&re);
                    820:        return (result);
                    821: }
                    822:
                    823: static int
                    824: magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
                    825: {
                    826:        const char      *cp, *endptr, *start, *found;
                    827:        size_t           size, end, i;
                    828:        uint64_t         range;
                    829:        int              result, n, cflag = 0, bflag = 0, Bflag = 0;
                    830:
                    831:        cp = &ml->type_string[(sizeof "search") - 1];
                    832:        if (*cp != '\0') {
                    833:                if (*cp != '/')
                    834:                        return (-1);
                    835:                cp++;
                    836:
                    837:                endptr = magic_strtoull(cp, &range);
                    838:                if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
                    839:                        return (-1);
                    840:
                    841:                if (*endptr == '/') {
                    842:                        for (cp = endptr + 1; *cp != '\0'; cp++) {
                    843:                                switch (*cp) {
                    844:                                case 'B':
                    845:                                        Bflag = 1;
                    846:                                        break;
                    847:                                case 'b':
                    848:                                        bflag = 1;
                    849:                                        break;
                    850:                                case 'c':
                    851:                                        cflag = 1;
                    852:                                        break;
                    853:                                default:
                    854:                                        return (-1);
                    855:                                }
                    856:                        }
                    857:                }
                    858:        } else
                    859:                range = UINT64_MAX;
                    860:        if (range > (uint64_t)ms->size - ms->offset)
                    861:                range = ms->size - ms->offset;
                    862:        size = ml->test_string_size;
                    863:
                    864:        /* Want to search every starting position from up to range + size. */
                    865:        end = range + size;
                    866:        if (end > ms->size - ms->offset) {
                    867:                if (size > ms->size - ms->offset)
                    868:                        end = 0;
                    869:                else
                    870:                        end = ms->size - ms->offset - size;
                    871:        }
                    872:
                    873:        /*
                    874:         * < and > and the flags are only in /etc/magic with search/1 so don't
                    875:         * support them with anything else.
                    876:         */
                    877:        start = ms->base + ms->offset;
                    878:        if (end == 0)
                    879:                found = NULL;
                    880:        else if (ml->test_operator == 'x')
                    881:                found = start;
                    882:        else if (range == 1) {
                    883:                n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
                    884:                    size, cflag, bflag, Bflag);
                    885:                if (n == -1 && ml->test_operator == '<')
                    886:                        found = start;
                    887:                else if (n == 1 && ml->test_operator == '>')
                    888:                        found = start;
                    889:                else if (n == 0 && ml->test_operator == '=')
                    890:                        found = start;
                    891:                else
                    892:                        found = NULL;
                    893:        } else {
                    894:                if (ml->test_operator != '=')
                    895:                        return (-2);
                    896:                for (i = 0; i < end; i++) {
                    897:                        n = magic_test_eq(start + i, ms->size - ms->offset - i,
                    898:                            ml->test_string, size, cflag, bflag, Bflag);
                    899:                        if (n == 0) {
                    900:                                found = start + i;
                    901:                                break;
                    902:                        }
                    903:                }
                    904:                if (i == end)
                    905:                        found = NULL;
                    906:        }
                    907:        result = (found != NULL);
                    908:
                    909:        if (result == !ml->test_not && ml->result != NULL && found != NULL) {
                    910:                magic_add_string(ms, ml, found, ms->size - ms->offset);
                    911:                ms->offset = found - start + size;
                    912:        }
                    913:        return (result);
                    914: }
                    915:
                    916: static int
                    917: magic_test_type_default(__unused struct magic_line *ml,
                    918:     __unused struct magic_state *ms)
                    919: {
                    920:        return (1);
                    921: }
                    922:
                    923: static int (*magic_test_functions[])(struct magic_line *,
                    924:     struct magic_state *) = {
                    925:        magic_test_type_none,
                    926:        magic_test_type_byte,
                    927:        magic_test_type_short,
                    928:        magic_test_type_long,
                    929:        magic_test_type_quad,
                    930:        magic_test_type_ubyte,
                    931:        magic_test_type_ushort,
                    932:        magic_test_type_ulong,
                    933:        magic_test_type_uquad,
                    934:        magic_test_type_float,
                    935:        magic_test_type_double,
                    936:        magic_test_type_string,
                    937:        magic_test_type_pstring,
                    938:        magic_test_type_date,
                    939:        magic_test_type_qdate,
                    940:        magic_test_type_date,
                    941:        magic_test_type_qdate,
                    942:        magic_test_type_udate,
                    943:        magic_test_type_uqdate,
                    944:        magic_test_type_udate,
                    945:        magic_test_type_qdate,
                    946:        magic_test_type_short,
                    947:        magic_test_type_long,
                    948:        magic_test_type_quad,
                    949:        magic_test_type_ushort,
                    950:        magic_test_type_ulong,
                    951:        magic_test_type_uquad,
                    952:        magic_test_type_float,
                    953:        magic_test_type_double,
                    954:        magic_test_type_date,
                    955:        magic_test_type_qdate,
                    956:        magic_test_type_date,
                    957:        magic_test_type_qdate,
                    958:        magic_test_type_udate,
                    959:        magic_test_type_uqdate,
                    960:        magic_test_type_udate,
                    961:        magic_test_type_uqdate,
                    962:        magic_test_type_bestring16,
                    963:        magic_test_type_short,
                    964:        magic_test_type_long,
                    965:        magic_test_type_quad,
                    966:        magic_test_type_ushort,
                    967:        magic_test_type_ulong,
                    968:        magic_test_type_uquad,
                    969:        magic_test_type_float,
                    970:        magic_test_type_double,
                    971:        magic_test_type_date,
                    972:        magic_test_type_qdate,
                    973:        magic_test_type_date,
                    974:        magic_test_type_qdate,
                    975:        magic_test_type_udate,
                    976:        magic_test_type_uqdate,
                    977:        magic_test_type_udate,
                    978:        magic_test_type_uqdate,
                    979:        magic_test_type_lestring16,
                    980:        magic_test_type_melong,
                    981:        magic_test_type_medate,
                    982:        magic_test_type_meldate,
                    983:        magic_test_type_regex,
                    984:        magic_test_type_search,
                    985:        magic_test_type_default,
                    986: };
                    987:
                    988: static int
                    989: magic_test_line(struct magic_line *ml, struct magic_state *ms)
                    990: {
                    991:        struct magic_line       *child;
                    992:        int64_t                  offset, wanted, next;
                    993:        int                      result;
                    994:        uint8_t                  b;
                    995:        uint16_t                 s;
                    996:        uint32_t                 l;
                    997:
                    998:        if (ml->indirect_type == ' ')
                    999:                wanted = ml->offset;
                   1000:        else {
                   1001:                wanted = ml->indirect_offset;
                   1002:                if (ml->indirect_relative) {
                   1003:                        if (wanted < 0 && -wanted > ms->offset)
                   1004:                                return (0);
                   1005:                        if (wanted > 0 && ms->offset + wanted > ms->size)
                   1006:                                return (0);
                   1007:                        next = ms->offset + ml->indirect_offset;
                   1008:                } else
                   1009:                        next = wanted;
                   1010:
                   1011:                switch (ml->indirect_type) {
                   1012:                case 'b':
                   1013:                case 'B':
                   1014:                        if (magic_copy_from(ms, next, &b, sizeof b) != 0)
                   1015:                                return (0);
                   1016:                        wanted = b;
                   1017:                        break;
                   1018:                case 's':
                   1019:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1020:                                return (0);
1.3       brynet   1021:                        wanted = le16toh(s);
1.1       nicm     1022:                        break;
                   1023:                case 'S':
                   1024:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1025:                                return (0);
1.3       brynet   1026:                        wanted = be16toh(s);
1.1       nicm     1027:                        break;
                   1028:                case 'l':
                   1029:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1030:                                return (0);
1.3       brynet   1031:                        wanted = le16toh(l);
1.1       nicm     1032:                        break;
                   1033:                case 'L':
                   1034:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1035:                                return (0);
1.3       brynet   1036:                        wanted = be16toh(l);
1.1       nicm     1037:                        break;
                   1038:                }
                   1039:
                   1040:                switch (ml->indirect_operator) {
                   1041:                case '+':
                   1042:                        wanted += ml->indirect_operand;
                   1043:                        break;
                   1044:                case '-':
                   1045:                        wanted -= ml->indirect_operand;
                   1046:                        break;
                   1047:                case '*':
                   1048:                        wanted *= ml->indirect_operand;
                   1049:                        break;
                   1050:                }
                   1051:        }
                   1052:
                   1053:        if (ml->offset_relative) {
                   1054:                if (wanted < 0 && -wanted > ms->offset)
                   1055:                        return (0);
                   1056:                if (wanted > 0 && ms->offset + wanted > ms->size)
                   1057:                        return (0);
                   1058:                offset = ms->offset + wanted;
                   1059:        } else
                   1060:                offset = wanted;
                   1061:        if (offset < 0 || offset > ms->size)
                   1062:                return (0);
                   1063:        ms->offset = offset;
                   1064:
                   1065:        result = magic_test_functions[ml->type](ml, ms);
                   1066:        if (result == -1) {
                   1067:                magic_warn(ml, "test %s/%c failed", ml->type_string,
                   1068:                    ml->test_operator);
                   1069:                return (0);
                   1070:        }
                   1071:        if (result == -2) {
                   1072:                magic_warn(ml, "test %s/%c not implemented", ml->type_string,
                   1073:                    ml->test_operator);
                   1074:                return (0);
                   1075:        }
                   1076:        if (result == ml->test_not)
                   1077:                return (0);
                   1078:        if (ml->mimetype != NULL)
                   1079:                ms->mimetype = ml->mimetype;
                   1080:
                   1081:        magic_warn(ml, "test %s/%c matched at offset %llu: '%s'",
                   1082:            ml->type_string, ml->test_operator, ms->offset,
                   1083:            ml->result == NULL ? "" : ml->result);
                   1084:
                   1085:        offset = ms->offset;
                   1086:        TAILQ_FOREACH(child, &ml->children, entry) {
                   1087:                ms->offset = offset;
                   1088:                magic_test_line(child, ms);
                   1089:        }
1.5     ! nicm     1090:        return (ml->result != NULL);
1.1       nicm     1091: }
                   1092:
                   1093: const char *
                   1094: magic_test(struct magic *m, const void *base, size_t size, int flags)
                   1095: {
                   1096:        struct magic_line               *ml;
                   1097:        static struct magic_state        ms;
                   1098:
                   1099:        memset(&ms, 0, sizeof ms);
                   1100:
                   1101:        ms.base = base;
                   1102:        ms.size = size;
                   1103:
                   1104:        ms.text = !!(flags & MAGIC_TEST_TEXT);
                   1105:
                   1106:        RB_FOREACH(ml, magic_tree, &m->tree) {
                   1107:                ms.offset = 0;
                   1108:                if (ml->text == ms.text && magic_test_line(ml, &ms))
                   1109:                        break;
                   1110:        }
                   1111:
                   1112:        if (*ms.out != '\0') {
                   1113:                if (flags & MAGIC_TEST_MIME) {
                   1114:                        if (ms.mimetype)
                   1115:                                return (xstrdup(ms.mimetype));
                   1116:                        return (NULL);
                   1117:                }
                   1118:                return (xstrdup(ms.out));
                   1119:        }
                   1120:        return (NULL);
                   1121: }