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

1.9     ! nicm        1: /* $OpenBSD: magic-test.c,v 1.8 2015/08/11 22:18:43 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
1.7       nicm      209: magic_test_double(struct magic_line *ml, double value, double wanted)
                    210: {
                    211:        switch (ml->test_operator) {
                    212:        case 'x':
                    213:                return (1);
                    214:        case '=':
                    215:                return (value == wanted);
                    216:        }
                    217:        return (-1);
                    218: }
                    219:
                    220: static int
1.1       nicm      221: magic_test_type_none(__unused struct magic_line *ml,
                    222:     __unused struct magic_state *ms)
                    223: {
                    224:        return (0);
                    225: }
                    226:
                    227: static int
                    228: magic_test_type_byte(struct magic_line *ml, struct magic_state *ms)
                    229: {
                    230:        int8_t  value;
                    231:        int     result;
                    232:
                    233:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    234:                return (0);
                    235:
                    236:        if (ml->type_operator == '&')
                    237:                value &= (int8_t)ml->type_operand;
1.8       nicm      238:        else if (ml->type_operator == '-')
                    239:                value -= (int8_t)ml->type_operand;
                    240:        else if (ml->type_operator == '+')
                    241:                value += (int8_t)ml->type_operand;
                    242:        else if (ml->type_operator == '/')
                    243:                value /= (int8_t)ml->type_operand;
                    244:        else if (ml->type_operator == '%')
                    245:                value %= (int8_t)ml->type_operand;
                    246:        else if (ml->type_operator == '*')
                    247:                value *= (int8_t)ml->type_operand;
1.1       nicm      248:        else if (ml->type_operator != ' ')
                    249:                return (-1);
                    250:
                    251:        result = magic_test_signed(ml, value, (int8_t)ml->test_signed);
                    252:        if (result == !ml->test_not && ml->result != NULL) {
                    253:                magic_add_result(ms, ml, "%c", (int)value);
                    254:                ms->offset += sizeof value;
                    255:        }
                    256:        return (result);
                    257: }
                    258:
                    259: static int
                    260: magic_test_type_short(struct magic_line *ml, struct magic_state *ms)
                    261: {
                    262:        int16_t value;
                    263:        int     result;
                    264:
                    265:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    266:                return (0);
                    267:        if (ml->type == MAGIC_TYPE_BESHORT)
1.3       brynet    268:                value = be16toh(value);
1.1       nicm      269:        if (ml->type == MAGIC_TYPE_LESHORT)
1.3       brynet    270:                value = le16toh(value);
1.1       nicm      271:
                    272:        if (ml->type_operator == '&')
                    273:                value &= (int16_t)ml->type_operand;
1.8       nicm      274:        else if (ml->type_operator == '-')
                    275:                value -= (int16_t)ml->type_operand;
                    276:        else if (ml->type_operator == '+')
                    277:                value += (int16_t)ml->type_operand;
                    278:        else if (ml->type_operator == '/')
                    279:                value /= (int16_t)ml->type_operand;
                    280:        else if (ml->type_operator == '%')
                    281:                value %= (int16_t)ml->type_operand;
                    282:        else if (ml->type_operator == '*')
                    283:                value *= (int16_t)ml->type_operand;
1.1       nicm      284:        else if (ml->type_operator != ' ')
                    285:                return (-1);
                    286:
                    287:        result = magic_test_signed(ml, value, (int16_t)ml->test_signed);
                    288:        if (result == !ml->test_not && ml->result != NULL) {
                    289:                magic_add_result(ms, ml, "%hd", (int)value);
                    290:                ms->offset += sizeof value;
                    291:        }
                    292:        return (result);
                    293: }
                    294:
                    295: static int
                    296: magic_test_type_long(struct magic_line *ml, struct magic_state *ms)
                    297: {
                    298:        int32_t value;
                    299:        int     result;
                    300:
                    301:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    302:                return (0);
                    303:        if (ml->type == MAGIC_TYPE_BELONG)
1.3       brynet    304:                value = be32toh(value);
1.1       nicm      305:        if (ml->type == MAGIC_TYPE_LELONG)
1.3       brynet    306:                value = le32toh(value);
1.1       nicm      307:
                    308:        if (ml->type_operator == '&')
                    309:                value &= (int32_t)ml->type_operand;
1.8       nicm      310:        else if (ml->type_operator == '-')
                    311:                value -= (int32_t)ml->type_operand;
                    312:        else if (ml->type_operator == '+')
                    313:                value += (int32_t)ml->type_operand;
                    314:        else if (ml->type_operator == '/')
                    315:                value /= (int32_t)ml->type_operand;
                    316:        else if (ml->type_operator == '%')
                    317:                value %= (int32_t)ml->type_operand;
                    318:        else if (ml->type_operator == '*')
                    319:                value *= (int32_t)ml->type_operand;
1.1       nicm      320:        else if (ml->type_operator != ' ')
                    321:                return (-1);
                    322:
                    323:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    324:        if (result == !ml->test_not && ml->result != NULL) {
                    325:                magic_add_result(ms, ml, "%d", (int)value);
                    326:                ms->offset += sizeof value;
                    327:        }
                    328:        return (result);
                    329: }
                    330:
                    331: static int
                    332: magic_test_type_quad(struct magic_line *ml, struct magic_state *ms)
                    333: {
                    334:        int64_t value;
                    335:        int     result;
                    336:
                    337:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    338:                return (0);
                    339:        if (ml->type == MAGIC_TYPE_BEQUAD)
1.3       brynet    340:                value = be64toh(value);
1.1       nicm      341:        if (ml->type == MAGIC_TYPE_LEQUAD)
1.3       brynet    342:                value = le64toh(value);
1.1       nicm      343:
                    344:        if (ml->type_operator == '&')
                    345:                value &= (int64_t)ml->type_operand;
1.8       nicm      346:        else if (ml->type_operator == '-')
                    347:                value -= (int64_t)ml->type_operand;
                    348:        else if (ml->type_operator == '+')
                    349:                value += (int64_t)ml->type_operand;
                    350:        else if (ml->type_operator == '/')
                    351:                value /= (int64_t)ml->type_operand;
                    352:        else if (ml->type_operator == '%')
                    353:                value %= (int64_t)ml->type_operand;
                    354:        else if (ml->type_operator == '*')
                    355:                value *= (int64_t)ml->type_operand;
1.1       nicm      356:        else if (ml->type_operator != ' ')
                    357:                return (-1);
                    358:
                    359:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    360:        if (result == !ml->test_not && ml->result != NULL) {
                    361:                magic_add_result(ms, ml, "%lld", (long long)value);
                    362:                ms->offset += sizeof value;
                    363:        }
                    364:        return (result);
                    365: }
                    366:
                    367: static int
                    368: magic_test_type_ubyte(struct magic_line *ml, struct magic_state *ms)
                    369: {
                    370:        uint8_t value;
                    371:        int     result;
                    372:
                    373:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    374:                return (0);
                    375:
                    376:        if (ml->type_operator == '&')
                    377:                value &= (uint8_t)ml->type_operand;
1.8       nicm      378:        else if (ml->type_operator == '-')
                    379:                value -= (uint8_t)ml->type_operand;
                    380:        else if (ml->type_operator == '+')
                    381:                value += (uint8_t)ml->type_operand;
                    382:        else if (ml->type_operator == '/')
                    383:                value /= (uint8_t)ml->type_operand;
                    384:        else if (ml->type_operator == '%')
                    385:                value %= (uint8_t)ml->type_operand;
                    386:        else if (ml->type_operator == '*')
                    387:                value *= (uint8_t)ml->type_operand;
1.1       nicm      388:        else if (ml->type_operator != ' ')
                    389:                return (-1);
                    390:
                    391:        result = magic_test_unsigned(ml, value, (uint8_t)ml->test_unsigned);
                    392:        if (result == !ml->test_not && ml->result != NULL) {
                    393:                magic_add_result(ms, ml, "%c", (unsigned int)value);
                    394:                ms->offset += sizeof value;
                    395:        }
                    396:        return (result);
                    397: }
                    398:
                    399: static int
                    400: magic_test_type_ushort(struct magic_line *ml, struct magic_state *ms)
                    401: {
                    402:        uint16_t        value;
                    403:        int             result;
                    404:
                    405:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    406:                return (0);
                    407:        if (ml->type == MAGIC_TYPE_UBESHORT)
1.3       brynet    408:                value = be16toh(value);
1.1       nicm      409:        if (ml->type == MAGIC_TYPE_ULESHORT)
1.3       brynet    410:                value = le16toh(value);
1.1       nicm      411:
                    412:        if (ml->type_operator == '&')
                    413:                value &= (uint16_t)ml->type_operand;
1.8       nicm      414:        else if (ml->type_operator == '-')
                    415:                value -= (uint16_t)ml->type_operand;
                    416:        else if (ml->type_operator == '+')
                    417:                value += (uint16_t)ml->type_operand;
                    418:        else if (ml->type_operator == '/')
                    419:                value /= (uint16_t)ml->type_operand;
                    420:        else if (ml->type_operator == '%')
                    421:                value %= (uint16_t)ml->type_operand;
                    422:        else if (ml->type_operator == '*')
                    423:                value *= (uint16_t)ml->type_operand;
1.1       nicm      424:        else if (ml->type_operator != ' ')
                    425:                return (-1);
                    426:
                    427:        result = magic_test_unsigned(ml, value, (uint16_t)ml->test_unsigned);
                    428:        if (result == !ml->test_not && ml->result != NULL) {
                    429:                magic_add_result(ms, ml, "%hu", (unsigned int)value);
                    430:                ms->offset += sizeof value;
                    431:        }
                    432:        return (result);
                    433: }
                    434:
                    435: static int
                    436: magic_test_type_ulong(struct magic_line *ml, struct magic_state *ms)
                    437: {
                    438:        uint32_t        value;
                    439:        int             result;
                    440:
                    441:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    442:                return (0);
                    443:        if (ml->type == MAGIC_TYPE_UBELONG)
1.3       brynet    444:                value = be32toh(value);
1.1       nicm      445:        if (ml->type == MAGIC_TYPE_ULELONG)
1.3       brynet    446:                value = le32toh(value);
1.1       nicm      447:
                    448:        if (ml->type_operator == '&')
                    449:                value &= (uint32_t)ml->type_operand;
1.8       nicm      450:        else if (ml->type_operator == '-')
                    451:                value -= (uint32_t)ml->type_operand;
                    452:        else if (ml->type_operator == '+')
                    453:                value += (uint32_t)ml->type_operand;
                    454:        else if (ml->type_operator == '/')
                    455:                value /= (uint32_t)ml->type_operand;
                    456:        else if (ml->type_operator == '%')
                    457:                value %= (uint32_t)ml->type_operand;
                    458:        else if (ml->type_operator == '*')
                    459:                value *= (uint32_t)ml->type_operand;
1.1       nicm      460:        else if (ml->type_operator != ' ')
                    461:                return (-1);
                    462:
                    463:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    464:        if (result == !ml->test_not && ml->result != NULL) {
                    465:                magic_add_result(ms, ml, "%u", (unsigned int)value);
                    466:                ms->offset += sizeof value;
                    467:        }
                    468:        return (result);
                    469: }
                    470:
                    471: static int
                    472: magic_test_type_uquad(struct magic_line *ml, struct magic_state *ms)
                    473: {
                    474:        uint64_t        value;
                    475:        int             result;
                    476:
                    477:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    478:                return (0);
                    479:        if (ml->type == MAGIC_TYPE_UBEQUAD)
1.3       brynet    480:                value = be64toh(value);
1.1       nicm      481:        if (ml->type == MAGIC_TYPE_ULEQUAD)
1.3       brynet    482:                value = le64toh(value);
1.1       nicm      483:
                    484:        if (ml->type_operator == '&')
                    485:                value &= (uint64_t)ml->type_operand;
1.8       nicm      486:        else if (ml->type_operator == '-')
                    487:                value -= (uint64_t)ml->type_operand;
                    488:        else if (ml->type_operator == '+')
                    489:                value += (uint64_t)ml->type_operand;
                    490:        else if (ml->type_operator == '/')
                    491:                value /= (uint64_t)ml->type_operand;
                    492:        else if (ml->type_operator == '%')
                    493:                value %= (uint64_t)ml->type_operand;
                    494:        else if (ml->type_operator == '*')
                    495:                value *= (uint64_t)ml->type_operand;
1.1       nicm      496:        else if (ml->type_operator != ' ')
                    497:                return (-1);
                    498:
                    499:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    500:        if (result == !ml->test_not && ml->result != NULL) {
                    501:                magic_add_result(ms, ml, "%llu", (unsigned long long)value);
                    502:                ms->offset += sizeof value;
                    503:        }
                    504:        return (result);
                    505: }
                    506:
                    507: static int
                    508: magic_test_type_float(struct magic_line *ml, struct magic_state *ms)
                    509: {
                    510:        uint32_t        value0;
                    511:        double          value;
1.7       nicm      512:        int             result;
1.1       nicm      513:
                    514:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    515:                return (0);
                    516:        if (ml->type == MAGIC_TYPE_BEFLOAT)
1.3       brynet    517:                value0 = be32toh(value0);
1.1       nicm      518:        if (ml->type == MAGIC_TYPE_LEFLOAT)
1.3       brynet    519:                value0 = le32toh(value0);
1.1       nicm      520:        memcpy(&value, &value0, sizeof value);
                    521:
                    522:        if (ml->type_operator != ' ')
                    523:                return (-1);
                    524:
1.7       nicm      525:        result = magic_test_double(ml, value, (float)ml->test_double);
                    526:        if (result == !ml->test_not && ml->result != NULL) {
                    527:                magic_add_result(ms, ml, "%g", value);
                    528:                ms->offset += sizeof value0;
                    529:        }
1.1       nicm      530:        return (1);
                    531: }
                    532:
                    533: static int
                    534: magic_test_type_double(struct magic_line *ml, struct magic_state *ms)
                    535: {
                    536:        uint64_t        value0;
                    537:        double          value;
1.7       nicm      538:        int             result;
1.1       nicm      539:
                    540:        if (magic_copy_from(ms, -1, &value0, sizeof value0) != 0)
                    541:                return (0);
                    542:        if (ml->type == MAGIC_TYPE_BEDOUBLE)
1.3       brynet    543:                value0 = be64toh(value0);
1.1       nicm      544:        if (ml->type == MAGIC_TYPE_LEDOUBLE)
1.3       brynet    545:                value0 = le64toh(value0);
1.1       nicm      546:        memcpy(&value, &value0, sizeof value);
                    547:
                    548:        if (ml->type_operator != ' ')
                    549:                return (-1);
                    550:
1.7       nicm      551:        result = magic_test_double(ml, value, (double)ml->test_double);
                    552:        if (result == !ml->test_not && ml->result != NULL) {
                    553:                magic_add_result(ms, ml, "%g", value);
                    554:                ms->offset += sizeof value0;
                    555:        }
1.1       nicm      556:        return (1);
                    557: }
                    558:
                    559: static int
                    560: magic_test_type_string(struct magic_line *ml, struct magic_state *ms)
                    561: {
                    562:        const char      *s, *cp;
                    563:        size_t           slen;
                    564:        int              result, cflag = 0, bflag = 0, Bflag = 0;
                    565:
                    566:        cp = &ml->type_string[(sizeof "string") - 1];
                    567:        if (*cp != '\0') {
                    568:                if (*cp != '/')
                    569:                        return (-1);
                    570:                cp++;
                    571:                for (; *cp != '\0'; cp++) {
                    572:                        switch (*cp) {
                    573:                        case 'B':
                    574:                                Bflag = 1;
                    575:                                break;
                    576:                        case 'b':
                    577:                                bflag = 1;
                    578:                                break;
                    579:                        case 'c':
                    580:                                cflag = 1;
                    581:                                break;
                    582:                        default:
                    583:                                return (-1);
                    584:                        }
                    585:                }
                    586:        }
                    587:
                    588:        s = ms->base + ms->offset;
                    589:        slen = ms->size - ms->offset;
                    590:        if (slen < ml->test_string_size)
                    591:                return (0);
                    592:
                    593:        result = magic_test_eq(s, slen, ml->test_string, ml->test_string_size,
                    594:            cflag, bflag, Bflag);
                    595:        switch (ml->test_operator) {
                    596:        case 'x':
                    597:                result = 1;
                    598:                break;
                    599:        case '<':
                    600:                result = result < 0;
                    601:                break;
                    602:        case '>':
                    603:                result = result > 0;
                    604:                break;
                    605:        case '=':
                    606:                result = result == 0;
                    607:                break;
                    608:        default:
                    609:                result = -1;
                    610:                break;
                    611:        }
                    612:        if (result == !ml->test_not) {
                    613:                if (ml->result != NULL)
                    614:                        magic_add_string(ms, ml, s, slen);
                    615:                if (result && ml->test_operator == '=')
                    616:                        ms->offset = s - ms->base + ml->test_string_size;
                    617:        }
                    618:        return (result);
                    619: }
                    620:
                    621: static int
                    622: magic_test_type_pstring(struct magic_line *ml, struct magic_state *ms)
                    623: {
1.9     ! nicm      624:        const char      *s, *cp;
1.1       nicm      625:        size_t           slen;
                    626:        int              result;
1.9     ! nicm      627:
        !           628:        cp = &ml->type_string[(sizeof "pstring") - 1];
        !           629:        if (*cp != '\0') {
        !           630:                if (*cp != '/')
        !           631:                        return (-1);
        !           632:                cp++;
        !           633:                for (; *cp != '\0'; cp++) {
        !           634:                        switch (*cp) {
        !           635:                        default:
        !           636:                                return (-1);
        !           637:                        }
        !           638:                }
        !           639:        }
1.1       nicm      640:
                    641:        s = ms->base + ms->offset;
                    642:        if (ms->size - ms->offset < 1)
                    643:                return (-1);
                    644:        slen = *(u_char *)s;
                    645:        if (slen > ms->size - ms->offset)
                    646:                return (-1);
                    647:        s++;
                    648:
                    649:        if (slen < ml->test_string_size)
                    650:                result = -1;
                    651:        else if (slen > ml->test_string_size)
                    652:                result = 1;
                    653:        else
                    654:                result = memcmp(s, ml->test_string, ml->test_string_size);
                    655:        switch (ml->test_operator) {
                    656:        case 'x':
                    657:                result = 1;
                    658:                break;
                    659:        case '<':
                    660:                result = result < 0;
                    661:                break;
                    662:        case '>':
                    663:                result = result > 0;
                    664:                break;
                    665:        case '=':
                    666:                result = result == 0;
                    667:                break;
                    668:        default:
                    669:                result = -1;
                    670:                break;
                    671:        }
                    672:        if (result == !ml->test_not) {
                    673:                if (ml->result != NULL)
                    674:                        magic_add_string(ms, ml, s, slen);
                    675:                if (result)
                    676:                        ms->offset += slen + 1;
                    677:        }
                    678:        return (result);
                    679: }
                    680:
                    681: static int
                    682: magic_test_type_date(struct magic_line *ml, struct magic_state *ms)
                    683: {
                    684:        int32_t value;
                    685:        int     result;
                    686:        time_t  t;
                    687:        char    s[64];
                    688:
                    689:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    690:                return (0);
                    691:        if (ml->type == MAGIC_TYPE_BEDATE ||
                    692:            ml->type == MAGIC_TYPE_BELDATE)
1.3       brynet    693:                value = be32toh(value);
1.1       nicm      694:        if (ml->type == MAGIC_TYPE_LEDATE ||
                    695:            ml->type == MAGIC_TYPE_LELDATE)
1.3       brynet    696:                value = le32toh(value);
1.1       nicm      697:
                    698:        if (ml->type_operator == '&')
                    699:                value &= (int32_t)ml->type_operand;
                    700:        else if (ml->type_operator != ' ')
                    701:                return (-1);
                    702:
                    703:        result = magic_test_signed(ml, value, (int32_t)ml->test_signed);
                    704:        if (result == !ml->test_not && ml->result != NULL) {
                    705:                t = value;
                    706:                switch (ml->type) {
                    707:                case MAGIC_TYPE_LDATE:
                    708:                case MAGIC_TYPE_LELDATE:
                    709:                case MAGIC_TYPE_BELDATE:
                    710:                        ctime_r(&t, s);
                    711:                        break;
                    712:                default:
1.6       nicm      713:                        asctime_r(gmtime(&t), s);
1.1       nicm      714:                        break;
                    715:                }
                    716:                s[strcspn(s, "\n")] = '\0';
                    717:                magic_add_result(ms, ml, "%s", s);
                    718:                ms->offset += sizeof value;
                    719:        }
                    720:        return (result);
                    721: }
                    722:
                    723: static int
                    724: magic_test_type_qdate(struct magic_line *ml, struct magic_state *ms)
                    725: {
                    726:        int64_t value;
                    727:        int     result;
                    728:        time_t  t;
                    729:        char    s[64];
                    730:
                    731:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    732:                return (0);
                    733:        if (ml->type == MAGIC_TYPE_BEQDATE ||
                    734:            ml->type == MAGIC_TYPE_BEQLDATE)
1.3       brynet    735:                value = be64toh(value);
1.1       nicm      736:        if (ml->type == MAGIC_TYPE_LEQDATE ||
                    737:            ml->type == MAGIC_TYPE_LEQLDATE)
1.3       brynet    738:                value = le64toh(value);
1.1       nicm      739:
                    740:        if (ml->type_operator == '&')
                    741:                value &= (int64_t)ml->type_operand;
                    742:        else if (ml->type_operator != ' ')
                    743:                return (-1);
                    744:
                    745:        result = magic_test_signed(ml, value, (int64_t)ml->test_signed);
                    746:        if (result == !ml->test_not && ml->result != NULL) {
                    747:                t = value;
                    748:                switch (ml->type) {
                    749:                case MAGIC_TYPE_QLDATE:
                    750:                case MAGIC_TYPE_LEQLDATE:
                    751:                case MAGIC_TYPE_BEQLDATE:
                    752:                        ctime_r(&t, s);
                    753:                        break;
                    754:                default:
1.6       nicm      755:                        asctime_r(gmtime(&t), s);
1.1       nicm      756:                        break;
                    757:                }
                    758:                s[strcspn(s, "\n")] = '\0';
                    759:                magic_add_result(ms, ml, "%s", s);
                    760:                ms->offset += sizeof value;
                    761:        }
                    762:        return (result);
                    763: }
                    764:
                    765: static int
                    766: magic_test_type_udate(struct magic_line *ml, struct magic_state *ms)
                    767: {
                    768:        uint32_t        value;
                    769:        int             result;
                    770:        time_t          t;
                    771:        char            s[64];
                    772:
                    773:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    774:                return (0);
                    775:        if (ml->type == MAGIC_TYPE_BEDATE ||
                    776:            ml->type == MAGIC_TYPE_BELDATE)
1.3       brynet    777:                value = be32toh(value);
1.1       nicm      778:        if (ml->type == MAGIC_TYPE_LEDATE ||
                    779:            ml->type == MAGIC_TYPE_LELDATE)
1.3       brynet    780:                value = le32toh(value);
1.1       nicm      781:
                    782:        if (ml->type_operator == '&')
                    783:                value &= (uint32_t)ml->type_operand;
                    784:        else if (ml->type_operator != ' ')
                    785:                return (-1);
                    786:
                    787:        result = magic_test_unsigned(ml, value, (uint32_t)ml->test_unsigned);
                    788:        if (result == !ml->test_not && ml->result != NULL) {
                    789:                t = value;
                    790:                switch (ml->type) {
                    791:                case MAGIC_TYPE_LDATE:
                    792:                case MAGIC_TYPE_LELDATE:
                    793:                case MAGIC_TYPE_BELDATE:
                    794:                        ctime_r(&t, s);
                    795:                        break;
                    796:                default:
                    797:                        asctime_r(gmtime(&t), s);
                    798:                        break;
                    799:                }
                    800:                s[strcspn(s, "\n")] = '\0';
                    801:                magic_add_result(ms, ml, "%s", s);
                    802:                ms->offset += sizeof value;
                    803:        }
                    804:        return (result);
                    805: }
                    806:
                    807: static int
                    808: magic_test_type_uqdate(struct magic_line *ml, struct magic_state *ms)
                    809: {
                    810:        uint64_t        value;
                    811:        int             result;
                    812:        time_t          t;
                    813:        char            s[64];
                    814:
                    815:        if (magic_copy_from(ms, -1, &value, sizeof value) != 0)
                    816:                return (0);
                    817:        if (ml->type == MAGIC_TYPE_UBEQDATE ||
                    818:            ml->type == MAGIC_TYPE_UBEQLDATE)
1.3       brynet    819:                value = be64toh(value);
1.1       nicm      820:        if (ml->type == MAGIC_TYPE_ULEQDATE ||
                    821:            ml->type == MAGIC_TYPE_ULEQLDATE)
1.3       brynet    822:                value = le64toh(value);
1.1       nicm      823:
                    824:        if (ml->type_operator == '&')
                    825:                value &= (uint64_t)ml->type_operand;
                    826:        else if (ml->type_operator != ' ')
                    827:                return (-1);
                    828:
                    829:        result = magic_test_unsigned(ml, value, (uint64_t)ml->test_unsigned);
                    830:        if (result == !ml->test_not && ml->result != NULL) {
                    831:                t = value;
                    832:                switch (ml->type) {
                    833:                case MAGIC_TYPE_UQLDATE:
                    834:                case MAGIC_TYPE_ULEQLDATE:
                    835:                case MAGIC_TYPE_UBEQLDATE:
                    836:                        ctime_r(&t, s);
                    837:                        break;
                    838:                default:
                    839:                        asctime_r(gmtime(&t), s);
                    840:                        break;
                    841:                }
                    842:                s[strcspn(s, "\n")] = '\0';
                    843:                magic_add_result(ms, ml, "%s", s);
                    844:                ms->offset += sizeof value;
                    845:        }
                    846:        return (result);
                    847: }
                    848:
                    849: static int
                    850: magic_test_type_bestring16(__unused struct magic_line *ml,
                    851:     __unused struct magic_state *ms)
                    852: {
                    853:        return (-2);
                    854: }
                    855:
                    856: static int
                    857: magic_test_type_lestring16(__unused struct magic_line *ml,
                    858:     __unused struct magic_state *ms)
                    859: {
                    860:        return (-2);
                    861: }
                    862:
                    863: static int
                    864: magic_test_type_melong(__unused struct magic_line *ml,
                    865:     __unused struct magic_state *ms)
                    866: {
                    867:        return (-2);
                    868: }
                    869:
                    870: static int
                    871: magic_test_type_medate(__unused struct magic_line *ml,
                    872:     __unused struct magic_state *ms)
                    873: {
                    874:        return (-2);
                    875: }
                    876:
                    877: static int
                    878: magic_test_type_meldate(__unused struct magic_line *ml,
                    879:     __unused struct magic_state *ms)
                    880: {
                    881:        return (-2);
                    882: }
                    883:
                    884: static int
                    885: magic_test_type_regex(struct magic_line *ml, struct magic_state *ms)
                    886: {
                    887:        const char      *cp;
                    888:        regex_t          re;
                    889:        regmatch_t       m;
                    890:        int              result, flags = 0, sflag = 0;
                    891:
                    892:        cp = &ml->type_string[(sizeof "regex") - 1];
                    893:        if (*cp != '\0') {
                    894:                if (*cp != '/')
                    895:                        return (-1);
                    896:                cp++;
                    897:                for (; *cp != '\0'; cp++) {
                    898:                        switch (*cp) {
                    899:                        case 's':
                    900:                                sflag = 1;
                    901:                                break;
                    902:                        case 'c':
                    903:                                flags |= REG_ICASE;
                    904:                                break;
                    905:                        default:
                    906:                                return (-1);
                    907:                        }
                    908:                }
                    909:        }
                    910:
                    911:        if (regcomp(&re, ml->test_string, REG_EXTENDED) != 0)
                    912:                return (-1);
                    913:        m.rm_so = ms->offset;
                    914:        m.rm_eo = ms->size;
                    915:
                    916:        result = (regexec(&re, ms->base, 1, &m, REG_STARTEND) == 0);
                    917:        if (result == !ml->test_not && ml->result != NULL) {
                    918:                magic_add_result(ms, ml, "%s", "");
                    919:                if (result) {
                    920:                        if (sflag)
                    921:                                ms->offset = m.rm_so;
                    922:                        else
                    923:                                ms->offset = m.rm_eo;
                    924:                }
                    925:        }
                    926:        regfree(&re);
                    927:        return (result);
                    928: }
                    929:
                    930: static int
                    931: magic_test_type_search(struct magic_line *ml, struct magic_state *ms)
                    932: {
                    933:        const char      *cp, *endptr, *start, *found;
                    934:        size_t           size, end, i;
                    935:        uint64_t         range;
                    936:        int              result, n, cflag = 0, bflag = 0, Bflag = 0;
                    937:
                    938:        cp = &ml->type_string[(sizeof "search") - 1];
                    939:        if (*cp != '\0') {
                    940:                if (*cp != '/')
                    941:                        return (-1);
                    942:                cp++;
                    943:
                    944:                endptr = magic_strtoull(cp, &range);
                    945:                if (endptr == NULL || (*endptr != '/' && *endptr != '\0'))
                    946:                        return (-1);
                    947:
                    948:                if (*endptr == '/') {
                    949:                        for (cp = endptr + 1; *cp != '\0'; cp++) {
                    950:                                switch (*cp) {
                    951:                                case 'B':
                    952:                                        Bflag = 1;
                    953:                                        break;
                    954:                                case 'b':
                    955:                                        bflag = 1;
                    956:                                        break;
                    957:                                case 'c':
                    958:                                        cflag = 1;
                    959:                                        break;
                    960:                                default:
                    961:                                        return (-1);
                    962:                                }
                    963:                        }
                    964:                }
                    965:        } else
                    966:                range = UINT64_MAX;
                    967:        if (range > (uint64_t)ms->size - ms->offset)
                    968:                range = ms->size - ms->offset;
                    969:        size = ml->test_string_size;
                    970:
                    971:        /* Want to search every starting position from up to range + size. */
                    972:        end = range + size;
                    973:        if (end > ms->size - ms->offset) {
                    974:                if (size > ms->size - ms->offset)
                    975:                        end = 0;
                    976:                else
                    977:                        end = ms->size - ms->offset - size;
                    978:        }
                    979:
                    980:        /*
                    981:         * < and > and the flags are only in /etc/magic with search/1 so don't
                    982:         * support them with anything else.
                    983:         */
                    984:        start = ms->base + ms->offset;
                    985:        if (end == 0)
                    986:                found = NULL;
                    987:        else if (ml->test_operator == 'x')
                    988:                found = start;
                    989:        else if (range == 1) {
                    990:                n = magic_test_eq(start, ms->size - ms->offset, ml->test_string,
                    991:                    size, cflag, bflag, Bflag);
                    992:                if (n == -1 && ml->test_operator == '<')
                    993:                        found = start;
                    994:                else if (n == 1 && ml->test_operator == '>')
                    995:                        found = start;
                    996:                else if (n == 0 && ml->test_operator == '=')
                    997:                        found = start;
                    998:                else
                    999:                        found = NULL;
                   1000:        } else {
                   1001:                if (ml->test_operator != '=')
                   1002:                        return (-2);
                   1003:                for (i = 0; i < end; i++) {
                   1004:                        n = magic_test_eq(start + i, ms->size - ms->offset - i,
                   1005:                            ml->test_string, size, cflag, bflag, Bflag);
                   1006:                        if (n == 0) {
                   1007:                                found = start + i;
                   1008:                                break;
                   1009:                        }
                   1010:                }
                   1011:                if (i == end)
                   1012:                        found = NULL;
                   1013:        }
                   1014:        result = (found != NULL);
                   1015:
                   1016:        if (result == !ml->test_not && ml->result != NULL && found != NULL) {
                   1017:                magic_add_string(ms, ml, found, ms->size - ms->offset);
                   1018:                ms->offset = found - start + size;
                   1019:        }
                   1020:        return (result);
                   1021: }
                   1022:
                   1023: static int
                   1024: magic_test_type_default(__unused struct magic_line *ml,
                   1025:     __unused struct magic_state *ms)
                   1026: {
                   1027:        return (1);
                   1028: }
                   1029:
                   1030: static int (*magic_test_functions[])(struct magic_line *,
                   1031:     struct magic_state *) = {
                   1032:        magic_test_type_none,
                   1033:        magic_test_type_byte,
                   1034:        magic_test_type_short,
                   1035:        magic_test_type_long,
                   1036:        magic_test_type_quad,
                   1037:        magic_test_type_ubyte,
                   1038:        magic_test_type_ushort,
                   1039:        magic_test_type_ulong,
                   1040:        magic_test_type_uquad,
                   1041:        magic_test_type_float,
                   1042:        magic_test_type_double,
                   1043:        magic_test_type_string,
                   1044:        magic_test_type_pstring,
                   1045:        magic_test_type_date,
                   1046:        magic_test_type_qdate,
                   1047:        magic_test_type_date,
                   1048:        magic_test_type_qdate,
                   1049:        magic_test_type_udate,
                   1050:        magic_test_type_uqdate,
                   1051:        magic_test_type_udate,
                   1052:        magic_test_type_qdate,
                   1053:        magic_test_type_short,
                   1054:        magic_test_type_long,
                   1055:        magic_test_type_quad,
                   1056:        magic_test_type_ushort,
                   1057:        magic_test_type_ulong,
                   1058:        magic_test_type_uquad,
                   1059:        magic_test_type_float,
                   1060:        magic_test_type_double,
                   1061:        magic_test_type_date,
                   1062:        magic_test_type_qdate,
                   1063:        magic_test_type_date,
                   1064:        magic_test_type_qdate,
                   1065:        magic_test_type_udate,
                   1066:        magic_test_type_uqdate,
                   1067:        magic_test_type_udate,
                   1068:        magic_test_type_uqdate,
                   1069:        magic_test_type_bestring16,
                   1070:        magic_test_type_short,
                   1071:        magic_test_type_long,
                   1072:        magic_test_type_quad,
                   1073:        magic_test_type_ushort,
                   1074:        magic_test_type_ulong,
                   1075:        magic_test_type_uquad,
                   1076:        magic_test_type_float,
                   1077:        magic_test_type_double,
                   1078:        magic_test_type_date,
                   1079:        magic_test_type_qdate,
                   1080:        magic_test_type_date,
                   1081:        magic_test_type_qdate,
                   1082:        magic_test_type_udate,
                   1083:        magic_test_type_uqdate,
                   1084:        magic_test_type_udate,
                   1085:        magic_test_type_uqdate,
                   1086:        magic_test_type_lestring16,
                   1087:        magic_test_type_melong,
                   1088:        magic_test_type_medate,
                   1089:        magic_test_type_meldate,
                   1090:        magic_test_type_regex,
                   1091:        magic_test_type_search,
                   1092:        magic_test_type_default,
                   1093: };
                   1094:
                   1095: static int
                   1096: magic_test_line(struct magic_line *ml, struct magic_state *ms)
                   1097: {
                   1098:        struct magic_line       *child;
                   1099:        int64_t                  offset, wanted, next;
                   1100:        int                      result;
                   1101:        uint8_t                  b;
                   1102:        uint16_t                 s;
                   1103:        uint32_t                 l;
                   1104:
                   1105:        if (ml->indirect_type == ' ')
                   1106:                wanted = ml->offset;
                   1107:        else {
                   1108:                wanted = ml->indirect_offset;
                   1109:                if (ml->indirect_relative) {
                   1110:                        if (wanted < 0 && -wanted > ms->offset)
                   1111:                                return (0);
                   1112:                        if (wanted > 0 && ms->offset + wanted > ms->size)
                   1113:                                return (0);
                   1114:                        next = ms->offset + ml->indirect_offset;
                   1115:                } else
                   1116:                        next = wanted;
                   1117:
                   1118:                switch (ml->indirect_type) {
                   1119:                case 'b':
                   1120:                case 'B':
                   1121:                        if (magic_copy_from(ms, next, &b, sizeof b) != 0)
                   1122:                                return (0);
                   1123:                        wanted = b;
                   1124:                        break;
                   1125:                case 's':
                   1126:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1127:                                return (0);
1.3       brynet   1128:                        wanted = le16toh(s);
1.1       nicm     1129:                        break;
                   1130:                case 'S':
                   1131:                        if (magic_copy_from(ms, next, &s, sizeof s) != 0)
                   1132:                                return (0);
1.3       brynet   1133:                        wanted = be16toh(s);
1.1       nicm     1134:                        break;
                   1135:                case 'l':
                   1136:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1137:                                return (0);
1.3       brynet   1138:                        wanted = le16toh(l);
1.1       nicm     1139:                        break;
                   1140:                case 'L':
                   1141:                        if (magic_copy_from(ms, next, &l, sizeof l) != 0)
                   1142:                                return (0);
1.3       brynet   1143:                        wanted = be16toh(l);
1.1       nicm     1144:                        break;
                   1145:                }
                   1146:
                   1147:                switch (ml->indirect_operator) {
                   1148:                case '+':
                   1149:                        wanted += ml->indirect_operand;
                   1150:                        break;
                   1151:                case '-':
                   1152:                        wanted -= ml->indirect_operand;
                   1153:                        break;
                   1154:                case '*':
                   1155:                        wanted *= ml->indirect_operand;
                   1156:                        break;
                   1157:                }
                   1158:        }
                   1159:
                   1160:        if (ml->offset_relative) {
                   1161:                if (wanted < 0 && -wanted > ms->offset)
                   1162:                        return (0);
                   1163:                if (wanted > 0 && ms->offset + wanted > ms->size)
                   1164:                        return (0);
                   1165:                offset = ms->offset + wanted;
                   1166:        } else
                   1167:                offset = wanted;
                   1168:        if (offset < 0 || offset > ms->size)
                   1169:                return (0);
                   1170:        ms->offset = offset;
                   1171:
                   1172:        result = magic_test_functions[ml->type](ml, ms);
                   1173:        if (result == -1) {
                   1174:                magic_warn(ml, "test %s/%c failed", ml->type_string,
                   1175:                    ml->test_operator);
                   1176:                return (0);
                   1177:        }
                   1178:        if (result == -2) {
                   1179:                magic_warn(ml, "test %s/%c not implemented", ml->type_string,
                   1180:                    ml->test_operator);
                   1181:                return (0);
                   1182:        }
                   1183:        if (result == ml->test_not)
                   1184:                return (0);
                   1185:        if (ml->mimetype != NULL)
                   1186:                ms->mimetype = ml->mimetype;
                   1187:
                   1188:        magic_warn(ml, "test %s/%c matched at offset %llu: '%s'",
                   1189:            ml->type_string, ml->test_operator, ms->offset,
                   1190:            ml->result == NULL ? "" : ml->result);
                   1191:
                   1192:        offset = ms->offset;
                   1193:        TAILQ_FOREACH(child, &ml->children, entry) {
                   1194:                ms->offset = offset;
                   1195:                magic_test_line(child, ms);
                   1196:        }
1.5       nicm     1197:        return (ml->result != NULL);
1.1       nicm     1198: }
                   1199:
                   1200: const char *
                   1201: magic_test(struct magic *m, const void *base, size_t size, int flags)
                   1202: {
                   1203:        struct magic_line               *ml;
                   1204:        static struct magic_state        ms;
                   1205:
                   1206:        memset(&ms, 0, sizeof ms);
                   1207:
                   1208:        ms.base = base;
                   1209:        ms.size = size;
                   1210:
                   1211:        ms.text = !!(flags & MAGIC_TEST_TEXT);
                   1212:
                   1213:        RB_FOREACH(ml, magic_tree, &m->tree) {
                   1214:                ms.offset = 0;
                   1215:                if (ml->text == ms.text && magic_test_line(ml, &ms))
                   1216:                        break;
                   1217:        }
                   1218:
                   1219:        if (*ms.out != '\0') {
                   1220:                if (flags & MAGIC_TEST_MIME) {
                   1221:                        if (ms.mimetype)
                   1222:                                return (xstrdup(ms.mimetype));
                   1223:                        return (NULL);
                   1224:                }
                   1225:                return (xstrdup(ms.out));
                   1226:        }
                   1227:        return (NULL);
                   1228: }