1 /* $NetBSD: softmagic.c,v 1.13 2015/01/02 21:15:32 christos Exp $ */
2
3 /*
4 * Copyright (c) Ian F. Darwin 1986-1995.
5 * Software written by Ian F. Darwin and others;
6 * maintained 1995-present by Christos Zoulas and others.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice immediately at the beginning of the file, without modification,
13 * this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30 /*
31 * softmagic - interpret variable magic from MAGIC
32 */
33
34 #include "file.h"
35
36 #ifndef lint
37 #if 0
38 FILE_RCSID("@(#)$File: softmagic.c,v 1.206 2015/01/01 17:07:34 christos Exp $")
39 #else
40 __RCSID("$NetBSD: softmagic.c,v 1.13 2015/01/02 21:15:32 christos Exp $");
41 #endif
42 #endif /* lint */
43
44 #include "magic.h"
45 #include <assert.h>
46 #include <string.h>
47 #include <ctype.h>
48 #include <stdlib.h>
49 #include <time.h>
50
51 private int match(struct magic_set *, struct magic *, uint32_t,
52 const unsigned char *, size_t, size_t, int, int, int, uint16_t,
53 uint16_t *, int *, int *, int *);
54 private int mget(struct magic_set *, const unsigned char *,
55 struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t,
56 uint16_t *, int *, int *, int *);
57 private int magiccheck(struct magic_set *, struct magic *);
58 private int32_t mprint(struct magic_set *, struct magic *);
59 private int32_t moffset(struct magic_set *, struct magic *);
60 private void mdebug(uint32_t, const char *, size_t);
61 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
62 const unsigned char *, uint32_t, size_t, struct magic *);
63 private int mconvert(struct magic_set *, struct magic *, int);
64 private int print_sep(struct magic_set *, int);
65 private int handle_annotation(struct magic_set *, struct magic *);
66 private void cvt_8(union VALUETYPE *, const struct magic *);
67 private void cvt_16(union VALUETYPE *, const struct magic *);
68 private void cvt_32(union VALUETYPE *, const struct magic *);
69 private void cvt_64(union VALUETYPE *, const struct magic *);
70
71 #define OFFSET_OOB(n, o, i) ((n) < (o) || (i) > ((n) - (o)))
72
73 /*
74 * softmagic - lookup one file in parsed, in-memory copy of database
75 * Passed the name and FILE * of one file to be typed.
76 */
77 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
78 protected int
file_softmagic(struct magic_set * ms,const unsigned char * buf,size_t nbytes,uint16_t indir_level,uint16_t * name_count,int mode,int text)79 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
80 uint16_t indir_level, uint16_t *name_count, int mode, int text)
81 {
82 struct mlist *ml;
83 int rv, printed_something = 0, need_separator = 0;
84 uint16_t nc;
85
86 if (name_count == NULL) {
87 nc = 0;
88 name_count = &nc;
89 }
90
91 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
92 if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
93 text, 0, indir_level, name_count,
94 &printed_something, &need_separator, NULL)) != 0)
95 return rv;
96
97 return 0;
98 }
99
100 #define FILE_FMTDEBUG
101 #ifdef FILE_FMTDEBUG
102 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
103
104 private const char * __attribute__((__format_arg__(3)))
file_fmtcheck(struct magic_set * ms,const struct magic * m,const char * def,const char * file,size_t line)105 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
106 const char *file, size_t line)
107 {
108 const char *ptr = fmtcheck(m->desc, def);
109 if (ptr == def)
110 file_magerror(ms,
111 "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
112 " with `%s'", file, line, m->desc, def);
113 return ptr;
114 }
115 #else
116 #define F(a, b, c) fmtcheck((b)->desc, (c))
117 #endif
118
119 /*
120 * Go through the whole list, stopping if you find a match. Process all
121 * the continuations of that match before returning.
122 *
123 * We support multi-level continuations:
124 *
125 * At any time when processing a successful top-level match, there is a
126 * current continuation level; it represents the level of the last
127 * successfully matched continuation.
128 *
129 * Continuations above that level are skipped as, if we see one, it
130 * means that the continuation that controls them - i.e, the
131 * lower-level continuation preceding them - failed to match.
132 *
133 * Continuations below that level are processed as, if we see one,
134 * it means we've finished processing or skipping higher-level
135 * continuations under the control of a successful or unsuccessful
136 * lower-level continuation, and are now seeing the next lower-level
137 * continuation and should process it. The current continuation
138 * level reverts to the level of the one we're seeing.
139 *
140 * Continuations at the current level are processed as, if we see
141 * one, there's no lower-level continuation that may have failed.
142 *
143 * If a continuation matches, we bump the current continuation level
144 * so that higher-level continuations are processed.
145 */
146 private int
match(struct magic_set * ms,struct magic * magic,uint32_t nmagic,const unsigned char * s,size_t nbytes,size_t offset,int mode,int text,int flip,uint16_t indir_level,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)147 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
148 const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
149 int flip, uint16_t indir_level, uint16_t *name_count,
150 int *printed_something, int *need_separator, int *returnval)
151 {
152 uint32_t magindex = 0;
153 unsigned int cont_level = 0;
154 int returnvalv = 0, e; /* if a match is found it is set to 1*/
155 int firstline = 1; /* a flag to print X\n X\n- X */
156 int print = (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0;
157
158 if (returnval == NULL)
159 returnval = &returnvalv;
160
161 if (file_check_mem(ms, cont_level) == -1)
162 return -1;
163
164 for (magindex = 0; magindex < nmagic; magindex++) {
165 int flush = 0;
166 struct magic *m = &magic[magindex];
167
168 if (m->type != FILE_NAME)
169 if ((IS_STRING(m->type) &&
170 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
171 ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
172 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
173 (m->flag & mode) != mode) {
174 /* Skip sub-tests */
175 while (magindex + 1 < nmagic &&
176 magic[magindex + 1].cont_level != 0 &&
177 ++magindex)
178 continue;
179 continue; /* Skip to next top-level test*/
180 }
181
182 ms->offset = m->offset;
183 ms->line = m->lineno;
184
185 /* if main entry matches, print it... */
186 switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
187 flip, indir_level, name_count,
188 printed_something, need_separator, returnval)) {
189 case -1:
190 return -1;
191 case 0:
192 flush = m->reln != '!';
193 break;
194 default:
195 if (m->type == FILE_INDIRECT)
196 *returnval = 1;
197
198 switch (magiccheck(ms, m)) {
199 case -1:
200 return -1;
201 case 0:
202 flush++;
203 break;
204 default:
205 flush = 0;
206 break;
207 }
208 break;
209 }
210 if (flush) {
211 /*
212 * main entry didn't match,
213 * flush its continuations
214 */
215 while (magindex < nmagic - 1 &&
216 magic[magindex + 1].cont_level != 0)
217 magindex++;
218 continue;
219 }
220
221 if ((e = handle_annotation(ms, m)) != 0) {
222 *need_separator = 1;
223 *printed_something = 1;
224 *returnval = 1;
225 return e;
226 }
227 /*
228 * If we are going to print something, we'll need to print
229 * a blank before we print something else.
230 */
231 if (*m->desc) {
232 *need_separator = 1;
233 *printed_something = 1;
234 if (print_sep(ms, firstline) == -1)
235 return -1;
236 }
237
238
239 if (print && mprint(ms, m) == -1)
240 return -1;
241
242 ms->c.li[cont_level].off = moffset(ms, m);
243
244 /* and any continuations that match */
245 if (file_check_mem(ms, ++cont_level) == -1)
246 return -1;
247
248 while (magindex + 1 < nmagic &&
249 magic[magindex + 1].cont_level != 0) {
250 m = &magic[++magindex];
251 ms->line = m->lineno; /* for messages */
252
253 if (cont_level < m->cont_level)
254 continue;
255 if (cont_level > m->cont_level) {
256 /*
257 * We're at the end of the level
258 * "cont_level" continuations.
259 */
260 cont_level = m->cont_level;
261 }
262 ms->offset = m->offset;
263 if (m->flag & OFFADD) {
264 ms->offset +=
265 ms->c.li[cont_level - 1].off;
266 }
267
268 #ifdef ENABLE_CONDITIONALS
269 if (m->cond == COND_ELSE ||
270 m->cond == COND_ELIF) {
271 if (ms->c.li[cont_level].last_match == 1)
272 continue;
273 }
274 #endif
275 switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
276 text, flip, indir_level, name_count,
277 printed_something, need_separator, returnval)) {
278 case -1:
279 return -1;
280 case 0:
281 if (m->reln != '!')
282 continue;
283 flush = 1;
284 break;
285 default:
286 if (m->type == FILE_INDIRECT)
287 *returnval = 1;
288 flush = 0;
289 break;
290 }
291
292 switch (flush ? 1 : magiccheck(ms, m)) {
293 case -1:
294 return -1;
295 case 0:
296 #ifdef ENABLE_CONDITIONALS
297 ms->c.li[cont_level].last_match = 0;
298 #endif
299 break;
300 default:
301 #ifdef ENABLE_CONDITIONALS
302 ms->c.li[cont_level].last_match = 1;
303 #endif
304 if (m->type == FILE_CLEAR)
305 ms->c.li[cont_level].got_match = 0;
306 else if (ms->c.li[cont_level].got_match) {
307 if (m->type == FILE_DEFAULT)
308 break;
309 } else
310 ms->c.li[cont_level].got_match = 1;
311 if ((e = handle_annotation(ms, m)) != 0) {
312 *need_separator = 1;
313 *printed_something = 1;
314 *returnval = 1;
315 return e;
316 }
317 /*
318 * If we are going to print something,
319 * make sure that we have a separator first.
320 */
321 if (*m->desc) {
322 if (!*printed_something) {
323 *printed_something = 1;
324 if (print_sep(ms, firstline)
325 == -1)
326 return -1;
327 }
328 }
329 /*
330 * This continuation matched. Print
331 * its message, with a blank before it
332 * if the previous item printed and
333 * this item isn't empty.
334 */
335 /* space if previous printed */
336 if (*need_separator
337 && ((m->flag & NOSPACE) == 0)
338 && *m->desc) {
339 if (print &&
340 file_printf(ms, " ") == -1)
341 return -1;
342 *need_separator = 0;
343 }
344 if (print && mprint(ms, m) == -1)
345 return -1;
346
347 ms->c.li[cont_level].off = moffset(ms, m);
348
349 if (*m->desc)
350 *need_separator = 1;
351
352 /*
353 * If we see any continuations
354 * at a higher level,
355 * process them.
356 */
357 if (file_check_mem(ms, ++cont_level) == -1)
358 return -1;
359 break;
360 }
361 }
362 if (*printed_something) {
363 firstline = 0;
364 if (print)
365 *returnval = 1;
366 }
367 if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
368 return *returnval; /* don't keep searching */
369 }
370 }
371 return *returnval; /* This is hit if -k is set or there is no match */
372 }
373
374 private int
check_fmt(struct magic_set * ms,struct magic * m)375 check_fmt(struct magic_set *ms, struct magic *m)
376 {
377 file_regex_t rx;
378 int rc, rv = -1;
379
380 if (strchr(m->desc, '%') == NULL)
381 return 0;
382
383 rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
384 if (rc) {
385 file_regerror(&rx, rc, ms);
386 } else {
387 rc = file_regexec(&rx, m->desc, 0, 0, 0);
388 rv = !rc;
389 }
390 file_regfree(&rx);
391 return rv;
392 }
393
394 #ifndef HAVE_STRNDUP
395 char * strndup(const char *, size_t);
396
397 char *
strndup(const char * str,size_t n)398 strndup(const char *str, size_t n)
399 {
400 size_t len;
401 char *copy;
402
403 for (len = 0; len < n && str[len]; len++)
404 continue;
405 if ((copy = malloc(len + 1)) == NULL)
406 return NULL;
407 (void)memcpy(copy, str, len);
408 copy[len] = '\0';
409 return copy;
410 }
411 #endif /* HAVE_STRNDUP */
412
413 private int32_t
mprint(struct magic_set * ms,struct magic * m)414 mprint(struct magic_set *ms, struct magic *m)
415 {
416 uint64_t v;
417 float vf;
418 double vd;
419 int64_t t = 0;
420 char buf[128], tbuf[26], sbuf[512];
421 union VALUETYPE *p = &ms->ms_value;
422
423 switch (m->type) {
424 case FILE_BYTE:
425 v = file_signextend(ms, m, (uint64_t)p->b);
426 switch (check_fmt(ms, m)) {
427 case -1:
428 return -1;
429 case 1:
430 (void)snprintf(buf, sizeof(buf), "%d",
431 (unsigned char)v);
432 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
433 return -1;
434 break;
435 default:
436 if (file_printf(ms, F(ms, m, "%d"),
437 (unsigned char) v) == -1)
438 return -1;
439 break;
440 }
441 t = ms->offset + sizeof(char);
442 break;
443
444 case FILE_SHORT:
445 case FILE_BESHORT:
446 case FILE_LESHORT:
447 v = file_signextend(ms, m, (uint64_t)p->h);
448 switch (check_fmt(ms, m)) {
449 case -1:
450 return -1;
451 case 1:
452 (void)snprintf(buf, sizeof(buf), "%u",
453 (unsigned short)v);
454 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
455 return -1;
456 break;
457 default:
458 if (file_printf(ms, F(ms, m, "%u"),
459 (unsigned short) v) == -1)
460 return -1;
461 break;
462 }
463 t = ms->offset + sizeof(short);
464 break;
465
466 case FILE_LONG:
467 case FILE_BELONG:
468 case FILE_LELONG:
469 case FILE_MELONG:
470 v = file_signextend(ms, m, (uint64_t)p->l);
471 switch (check_fmt(ms, m)) {
472 case -1:
473 return -1;
474 case 1:
475 (void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
476 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
477 return -1;
478 break;
479 default:
480 if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
481 return -1;
482 break;
483 }
484 t = ms->offset + sizeof(int32_t);
485 break;
486
487 case FILE_QUAD:
488 case FILE_BEQUAD:
489 case FILE_LEQUAD:
490 v = file_signextend(ms, m, p->q);
491 switch (check_fmt(ms, m)) {
492 case -1:
493 return -1;
494 case 1:
495 (void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
496 (unsigned long long)v);
497 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
498 return -1;
499 break;
500 default:
501 if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
502 (unsigned long long) v) == -1)
503 return -1;
504 break;
505 }
506 t = ms->offset + sizeof(int64_t);
507 break;
508
509 case FILE_STRING:
510 case FILE_PSTRING:
511 case FILE_BESTRING16:
512 case FILE_LESTRING16:
513 if (m->reln == '=' || m->reln == '!') {
514 if (file_printf(ms, F(ms, m, "%s"),
515 file_printable(sbuf, sizeof(sbuf), m->value.s))
516 == -1)
517 return -1;
518 t = ms->offset + m->vallen;
519 }
520 else {
521 char *str = p->s;
522
523 /* compute t before we mangle the string? */
524 t = ms->offset + strlen(str);
525
526 if (*m->value.s == '\0')
527 str[strcspn(str, "\n")] = '\0';
528
529 if (m->str_flags & STRING_TRIM) {
530 char *last;
531 while (isspace((unsigned char)*str))
532 str++;
533 last = str;
534 while (*last)
535 last++;
536 --last;
537 while (isspace((unsigned char)*last))
538 last--;
539 *++last = '\0';
540 }
541
542 if (file_printf(ms, F(ms, m, "%s"),
543 file_printable(sbuf, sizeof(sbuf), str)) == -1)
544 return -1;
545
546 if (m->type == FILE_PSTRING)
547 t += file_pstring_length_size(m);
548 }
549 break;
550
551 case FILE_DATE:
552 case FILE_BEDATE:
553 case FILE_LEDATE:
554 case FILE_MEDATE:
555 if (file_printf(ms, F(ms, m, "%s"),
556 file_fmttime(p->l + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
557 return -1;
558 t = ms->offset + sizeof(uint32_t);
559 break;
560
561 case FILE_LDATE:
562 case FILE_BELDATE:
563 case FILE_LELDATE:
564 case FILE_MELDATE:
565 if (file_printf(ms, F(ms, m, "%s"),
566 file_fmttime(p->l + m->num_mask, 0, tbuf)) == -1)
567 return -1;
568 t = ms->offset + sizeof(uint32_t);
569 break;
570
571 case FILE_QDATE:
572 case FILE_BEQDATE:
573 case FILE_LEQDATE:
574 if (file_printf(ms, F(ms, m, "%s"),
575 file_fmttime(p->q + m->num_mask, FILE_T_LOCAL, tbuf)) == -1)
576 return -1;
577 t = ms->offset + sizeof(uint64_t);
578 break;
579
580 case FILE_QLDATE:
581 case FILE_BEQLDATE:
582 case FILE_LEQLDATE:
583 if (file_printf(ms, F(ms, m, "%s"),
584 file_fmttime(p->q + m->num_mask, 0, tbuf)) == -1)
585 return -1;
586 t = ms->offset + sizeof(uint64_t);
587 break;
588
589 case FILE_QWDATE:
590 case FILE_BEQWDATE:
591 case FILE_LEQWDATE:
592 if (file_printf(ms, F(ms, m, "%s"),
593 file_fmttime(p->q + m->num_mask, FILE_T_WINDOWS, tbuf)) == -1)
594 return -1;
595 t = ms->offset + sizeof(uint64_t);
596 break;
597
598 case FILE_FLOAT:
599 case FILE_BEFLOAT:
600 case FILE_LEFLOAT:
601 vf = p->f;
602 switch (check_fmt(ms, m)) {
603 case -1:
604 return -1;
605 case 1:
606 (void)snprintf(buf, sizeof(buf), "%g", vf);
607 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
608 return -1;
609 break;
610 default:
611 if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
612 return -1;
613 break;
614 }
615 t = ms->offset + sizeof(float);
616 break;
617
618 case FILE_DOUBLE:
619 case FILE_BEDOUBLE:
620 case FILE_LEDOUBLE:
621 vd = p->d;
622 switch (check_fmt(ms, m)) {
623 case -1:
624 return -1;
625 case 1:
626 (void)snprintf(buf, sizeof(buf), "%g", vd);
627 if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
628 return -1;
629 break;
630 default:
631 if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
632 return -1;
633 break;
634 }
635 t = ms->offset + sizeof(double);
636 break;
637
638 case FILE_REGEX: {
639 char *cp;
640 int rval;
641
642 cp = strndup((const char *)ms->search.s, ms->search.rm_len);
643 if (cp == NULL) {
644 file_oomem(ms, ms->search.rm_len);
645 return -1;
646 }
647 rval = file_printf(ms, F(ms, m, "%s"),
648 file_printable(sbuf, sizeof(sbuf), cp));
649 free(cp);
650
651 if (rval == -1)
652 return -1;
653
654 if ((m->str_flags & REGEX_OFFSET_START))
655 t = ms->search.offset;
656 else
657 t = ms->search.offset + ms->search.rm_len;
658 break;
659 }
660
661 case FILE_SEARCH:
662 if (file_printf(ms, F(ms, m, "%s"),
663 file_printable(sbuf, sizeof(sbuf), m->value.s)) == -1)
664 return -1;
665 if ((m->str_flags & REGEX_OFFSET_START))
666 t = ms->search.offset;
667 else
668 t = ms->search.offset + m->vallen;
669 break;
670
671 case FILE_DEFAULT:
672 case FILE_CLEAR:
673 if (file_printf(ms, "%s", m->desc) == -1)
674 return -1;
675 t = ms->offset;
676 break;
677
678 case FILE_INDIRECT:
679 case FILE_USE:
680 case FILE_NAME:
681 t = ms->offset;
682 break;
683
684 default:
685 file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
686 return -1;
687 }
688 return (int32_t)t;
689 }
690
691 private int32_t
moffset(struct magic_set * ms,struct magic * m)692 moffset(struct magic_set *ms, struct magic *m)
693 {
694 switch (m->type) {
695 case FILE_BYTE:
696 return CAST(int32_t, (ms->offset + sizeof(char)));
697
698 case FILE_SHORT:
699 case FILE_BESHORT:
700 case FILE_LESHORT:
701 return CAST(int32_t, (ms->offset + sizeof(short)));
702
703 case FILE_LONG:
704 case FILE_BELONG:
705 case FILE_LELONG:
706 case FILE_MELONG:
707 return CAST(int32_t, (ms->offset + sizeof(int32_t)));
708
709 case FILE_QUAD:
710 case FILE_BEQUAD:
711 case FILE_LEQUAD:
712 return CAST(int32_t, (ms->offset + sizeof(int64_t)));
713
714 case FILE_STRING:
715 case FILE_PSTRING:
716 case FILE_BESTRING16:
717 case FILE_LESTRING16:
718 if (m->reln == '=' || m->reln == '!')
719 return ms->offset + m->vallen;
720 else {
721 union VALUETYPE *p = &ms->ms_value;
722 uint32_t t;
723
724 if (*m->value.s == '\0')
725 p->s[strcspn(p->s, "\n")] = '\0';
726 t = CAST(uint32_t, (ms->offset + strlen(p->s)));
727 if (m->type == FILE_PSTRING)
728 t += (uint32_t)file_pstring_length_size(m);
729 return t;
730 }
731
732 case FILE_DATE:
733 case FILE_BEDATE:
734 case FILE_LEDATE:
735 case FILE_MEDATE:
736 return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
737
738 case FILE_LDATE:
739 case FILE_BELDATE:
740 case FILE_LELDATE:
741 case FILE_MELDATE:
742 return CAST(int32_t, (ms->offset + sizeof(uint32_t)));
743
744 case FILE_QDATE:
745 case FILE_BEQDATE:
746 case FILE_LEQDATE:
747 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
748
749 case FILE_QLDATE:
750 case FILE_BEQLDATE:
751 case FILE_LEQLDATE:
752 return CAST(int32_t, (ms->offset + sizeof(uint64_t)));
753
754 case FILE_FLOAT:
755 case FILE_BEFLOAT:
756 case FILE_LEFLOAT:
757 return CAST(int32_t, (ms->offset + sizeof(float)));
758
759 case FILE_DOUBLE:
760 case FILE_BEDOUBLE:
761 case FILE_LEDOUBLE:
762 return CAST(int32_t, (ms->offset + sizeof(double)));
763
764 case FILE_REGEX:
765 if ((m->str_flags & REGEX_OFFSET_START) != 0)
766 return CAST(int32_t, ms->search.offset);
767 else
768 return CAST(int32_t, (ms->search.offset +
769 ms->search.rm_len));
770
771 case FILE_SEARCH:
772 if ((m->str_flags & REGEX_OFFSET_START) != 0)
773 return CAST(int32_t, ms->search.offset);
774 else
775 return CAST(int32_t, (ms->search.offset + m->vallen));
776
777 case FILE_CLEAR:
778 case FILE_DEFAULT:
779 case FILE_INDIRECT:
780 return ms->offset;
781
782 default:
783 return 0;
784 }
785 }
786
787 private int
cvt_flip(int type,int flip)788 cvt_flip(int type, int flip)
789 {
790 if (flip == 0)
791 return type;
792 switch (type) {
793 case FILE_BESHORT:
794 return FILE_LESHORT;
795 case FILE_BELONG:
796 return FILE_LELONG;
797 case FILE_BEDATE:
798 return FILE_LEDATE;
799 case FILE_BELDATE:
800 return FILE_LELDATE;
801 case FILE_BEQUAD:
802 return FILE_LEQUAD;
803 case FILE_BEQDATE:
804 return FILE_LEQDATE;
805 case FILE_BEQLDATE:
806 return FILE_LEQLDATE;
807 case FILE_BEQWDATE:
808 return FILE_LEQWDATE;
809 case FILE_LESHORT:
810 return FILE_BESHORT;
811 case FILE_LELONG:
812 return FILE_BELONG;
813 case FILE_LEDATE:
814 return FILE_BEDATE;
815 case FILE_LELDATE:
816 return FILE_BELDATE;
817 case FILE_LEQUAD:
818 return FILE_BEQUAD;
819 case FILE_LEQDATE:
820 return FILE_BEQDATE;
821 case FILE_LEQLDATE:
822 return FILE_BEQLDATE;
823 case FILE_LEQWDATE:
824 return FILE_BEQWDATE;
825 case FILE_BEFLOAT:
826 return FILE_LEFLOAT;
827 case FILE_LEFLOAT:
828 return FILE_BEFLOAT;
829 case FILE_BEDOUBLE:
830 return FILE_LEDOUBLE;
831 case FILE_LEDOUBLE:
832 return FILE_BEDOUBLE;
833 default:
834 return type;
835 }
836 }
837 #define DO_CVT(fld, cast) \
838 if (m->num_mask) \
839 switch (m->mask_op & FILE_OPS_MASK) { \
840 case FILE_OPAND: \
841 p->fld &= cast m->num_mask; \
842 break; \
843 case FILE_OPOR: \
844 p->fld |= cast m->num_mask; \
845 break; \
846 case FILE_OPXOR: \
847 p->fld ^= cast m->num_mask; \
848 break; \
849 case FILE_OPADD: \
850 p->fld += cast m->num_mask; \
851 break; \
852 case FILE_OPMINUS: \
853 p->fld -= cast m->num_mask; \
854 break; \
855 case FILE_OPMULTIPLY: \
856 p->fld *= cast m->num_mask; \
857 break; \
858 case FILE_OPDIVIDE: \
859 p->fld /= cast m->num_mask; \
860 break; \
861 case FILE_OPMODULO: \
862 p->fld %= cast m->num_mask; \
863 break; \
864 } \
865 if (m->mask_op & FILE_OPINVERSE) \
866 p->fld = ~p->fld \
867
868 private void
cvt_8(union VALUETYPE * p,const struct magic * m)869 cvt_8(union VALUETYPE *p, const struct magic *m)
870 {
871 DO_CVT(b, (uint8_t));
872 }
873
874 private void
cvt_16(union VALUETYPE * p,const struct magic * m)875 cvt_16(union VALUETYPE *p, const struct magic *m)
876 {
877 DO_CVT(h, (uint16_t));
878 }
879
880 private void
cvt_32(union VALUETYPE * p,const struct magic * m)881 cvt_32(union VALUETYPE *p, const struct magic *m)
882 {
883 DO_CVT(l, (uint32_t));
884 }
885
886 private void
cvt_64(union VALUETYPE * p,const struct magic * m)887 cvt_64(union VALUETYPE *p, const struct magic *m)
888 {
889 DO_CVT(q, (uint64_t));
890 }
891
892 #define DO_CVT2(fld, cast) \
893 if (m->num_mask) \
894 switch (m->mask_op & FILE_OPS_MASK) { \
895 case FILE_OPADD: \
896 p->fld += cast m->num_mask; \
897 break; \
898 case FILE_OPMINUS: \
899 p->fld -= cast m->num_mask; \
900 break; \
901 case FILE_OPMULTIPLY: \
902 p->fld *= cast m->num_mask; \
903 break; \
904 case FILE_OPDIVIDE: \
905 p->fld /= cast m->num_mask; \
906 break; \
907 } \
908
909 private void
cvt_float(union VALUETYPE * p,const struct magic * m)910 cvt_float(union VALUETYPE *p, const struct magic *m)
911 {
912 DO_CVT2(f, (float));
913 }
914
915 private void
cvt_double(union VALUETYPE * p,const struct magic * m)916 cvt_double(union VALUETYPE *p, const struct magic *m)
917 {
918 DO_CVT2(d, (double));
919 }
920
921 /*
922 * Convert the byte order of the data we are looking at
923 * While we're here, let's apply the mask operation
924 * (unless you have a better idea)
925 */
926 private int
mconvert(struct magic_set * ms,struct magic * m,int flip)927 mconvert(struct magic_set *ms, struct magic *m, int flip)
928 {
929 union VALUETYPE *p = &ms->ms_value;
930 uint8_t type;
931
932 switch (type = cvt_flip(m->type, flip)) {
933 case FILE_BYTE:
934 cvt_8(p, m);
935 return 1;
936 case FILE_SHORT:
937 cvt_16(p, m);
938 return 1;
939 case FILE_LONG:
940 case FILE_DATE:
941 case FILE_LDATE:
942 cvt_32(p, m);
943 return 1;
944 case FILE_QUAD:
945 case FILE_QDATE:
946 case FILE_QLDATE:
947 case FILE_QWDATE:
948 cvt_64(p, m);
949 return 1;
950 case FILE_STRING:
951 case FILE_BESTRING16:
952 case FILE_LESTRING16: {
953 /* Null terminate and eat *trailing* return */
954 p->s[sizeof(p->s) - 1] = '\0';
955 return 1;
956 }
957 case FILE_PSTRING: {
958 size_t sz = file_pstring_length_size(m);
959 char *ptr1 = p->s, *ptr2 = ptr1 + sz;
960 size_t len = file_pstring_get_length(m, ptr1);
961 sz = sizeof(p->s) - sz; /* maximum length of string */
962 if (len >= sz) {
963 /*
964 * The size of the pascal string length (sz)
965 * is 1, 2, or 4. We need at least 1 byte for NUL
966 * termination, but we've already truncated the
967 * string by p->s, so we need to deduct sz.
968 * Because we can use one of the bytes of the length
969 * after we shifted as NUL termination.
970 */
971 len = sz;
972 }
973 while (len--)
974 *ptr1++ = *ptr2++;
975 *ptr1 = '\0';
976 return 1;
977 }
978 case FILE_BESHORT:
979 p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
980 cvt_16(p, m);
981 return 1;
982 case FILE_BELONG:
983 case FILE_BEDATE:
984 case FILE_BELDATE:
985 p->l = (int32_t)
986 ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
987 if (type == FILE_BELONG)
988 cvt_32(p, m);
989 return 1;
990 case FILE_BEQUAD:
991 case FILE_BEQDATE:
992 case FILE_BEQLDATE:
993 case FILE_BEQWDATE:
994 p->q = (uint64_t)
995 (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
996 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
997 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
998 ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
999 if (type == FILE_BEQUAD)
1000 cvt_64(p, m);
1001 return 1;
1002 case FILE_LESHORT:
1003 p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
1004 cvt_16(p, m);
1005 return 1;
1006 case FILE_LELONG:
1007 case FILE_LEDATE:
1008 case FILE_LELDATE:
1009 p->l = (int32_t)
1010 ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
1011 if (type == FILE_LELONG)
1012 cvt_32(p, m);
1013 return 1;
1014 case FILE_LEQUAD:
1015 case FILE_LEQDATE:
1016 case FILE_LEQLDATE:
1017 case FILE_LEQWDATE:
1018 p->q = (uint64_t)
1019 (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1020 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1021 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1022 ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
1023 if (type == FILE_LEQUAD)
1024 cvt_64(p, m);
1025 return 1;
1026 case FILE_MELONG:
1027 case FILE_MEDATE:
1028 case FILE_MELDATE:
1029 p->l = (int32_t)
1030 ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
1031 if (type == FILE_MELONG)
1032 cvt_32(p, m);
1033 return 1;
1034 case FILE_FLOAT:
1035 cvt_float(p, m);
1036 return 1;
1037 case FILE_BEFLOAT:
1038 p->l = ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
1039 ((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
1040 cvt_float(p, m);
1041 return 1;
1042 case FILE_LEFLOAT:
1043 p->l = ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
1044 ((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
1045 cvt_float(p, m);
1046 return 1;
1047 case FILE_DOUBLE:
1048 cvt_double(p, m);
1049 return 1;
1050 case FILE_BEDOUBLE:
1051 p->q = ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
1052 ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
1053 ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
1054 ((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
1055 cvt_double(p, m);
1056 return 1;
1057 case FILE_LEDOUBLE:
1058 p->q = ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
1059 ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
1060 ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
1061 ((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
1062 cvt_double(p, m);
1063 return 1;
1064 case FILE_REGEX:
1065 case FILE_SEARCH:
1066 case FILE_DEFAULT:
1067 case FILE_CLEAR:
1068 case FILE_NAME:
1069 case FILE_USE:
1070 return 1;
1071 default:
1072 file_magerror(ms, "invalid type %d in mconvert()", m->type);
1073 return 0;
1074 }
1075 }
1076
1077
1078 private void
mdebug(uint32_t offset,const char * str,size_t len)1079 mdebug(uint32_t offset, const char *str, size_t len)
1080 {
1081 (void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1082 file_showstr(stderr, str, len);
1083 (void) fputc('\n', stderr);
1084 (void) fputc('\n', stderr);
1085 }
1086
1087 private int
mcopy(struct magic_set * ms,union VALUETYPE * p,int type,int indir,const unsigned char * s,uint32_t offset,size_t nbytes,struct magic * m)1088 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1089 const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1090 {
1091 /*
1092 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1093 * anything, but setup pointers into the source
1094 */
1095 if (indir == 0) {
1096 switch (type) {
1097 case FILE_SEARCH:
1098 ms->search.s = RCAST(const char *, s) + offset;
1099 ms->search.s_len = nbytes - offset;
1100 ms->search.offset = offset;
1101 return 0;
1102
1103 case FILE_REGEX: {
1104 const char *b;
1105 const char *c;
1106 const char *last; /* end of search region */
1107 const char *buf; /* start of search region */
1108 const char *end;
1109 size_t lines, linecnt, bytecnt;
1110
1111 if (s == NULL) {
1112 ms->search.s_len = 0;
1113 ms->search.s = NULL;
1114 return 0;
1115 }
1116
1117 if (m->str_flags & REGEX_LINE_COUNT) {
1118 linecnt = m->str_range;
1119 bytecnt = linecnt * 80;
1120 } else {
1121 linecnt = 0;
1122 bytecnt = m->str_range;
1123 }
1124
1125 if (bytecnt == 0)
1126 bytecnt = 8192;
1127 if (bytecnt > nbytes)
1128 bytecnt = nbytes;
1129
1130 buf = RCAST(const char *, s) + offset;
1131 end = last = RCAST(const char *, s) + bytecnt;
1132 /* mget() guarantees buf <= last */
1133 for (lines = linecnt, b = buf; lines && b < end &&
1134 ((b = CAST(const char *,
1135 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1136 || (b = CAST(const char *,
1137 memchr(c, '\r', CAST(size_t, (end - c))))));
1138 lines--, b++) {
1139 last = b;
1140 if (b[0] == '\r' && b[1] == '\n')
1141 b++;
1142 }
1143 if (lines)
1144 last = RCAST(const char *, s) + bytecnt;
1145
1146 ms->search.s = buf;
1147 ms->search.s_len = last - buf;
1148 ms->search.offset = offset;
1149 ms->search.rm_len = 0;
1150 return 0;
1151 }
1152 case FILE_BESTRING16:
1153 case FILE_LESTRING16: {
1154 const unsigned char *src = s + offset;
1155 const unsigned char *esrc = s + nbytes;
1156 char *dst = p->s;
1157 char *edst = &p->s[sizeof(p->s) - 1];
1158
1159 if (type == FILE_BESTRING16)
1160 src++;
1161
1162 /* check that offset is within range */
1163 if (offset >= nbytes)
1164 break;
1165 for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1166 if (dst < edst)
1167 *dst = *src;
1168 else
1169 break;
1170 if (*dst == '\0') {
1171 if (type == FILE_BESTRING16 ?
1172 *(src - 1) != '\0' :
1173 *(src + 1) != '\0')
1174 *dst = ' ';
1175 }
1176 }
1177 *edst = '\0';
1178 return 0;
1179 }
1180 case FILE_STRING: /* XXX - these two should not need */
1181 case FILE_PSTRING: /* to copy anything, but do anyway. */
1182 default:
1183 break;
1184 }
1185 }
1186
1187 if (offset >= nbytes) {
1188 (void)memset(p, '\0', sizeof(*p));
1189 return 0;
1190 }
1191 if (nbytes - offset < sizeof(*p))
1192 nbytes = nbytes - offset;
1193 else
1194 nbytes = sizeof(*p);
1195
1196 (void)memcpy(p, s + offset, nbytes);
1197
1198 /*
1199 * the usefulness of padding with zeroes eludes me, it
1200 * might even cause problems
1201 */
1202 if (nbytes < sizeof(*p))
1203 (void)memset(((char *)(void *)p) + nbytes, '\0',
1204 sizeof(*p) - nbytes);
1205 return 0;
1206 }
1207
1208 private int
mget(struct magic_set * ms,const unsigned char * s,struct magic * m,size_t nbytes,size_t o,unsigned int cont_level,int mode,int text,int flip,uint16_t indir_level,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)1209 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1210 size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1211 int flip, uint16_t indir_level, uint16_t *name_count,
1212 int *printed_something, int *need_separator, int *returnval)
1213 {
1214 uint32_t offset = ms->offset;
1215 uint32_t lhs;
1216 file_pushbuf_t *pb;
1217 int rv, oneed_separator, in_type;
1218 char *rbuf;
1219 union VALUETYPE *p = &ms->ms_value;
1220 struct mlist ml;
1221
1222 if (indir_level >= ms->indir_max) {
1223 file_error(ms, 0, "indirect recursion nesting (%hu) exceeded",
1224 indir_level);
1225 return -1;
1226 }
1227
1228 if (*name_count >= ms->name_max) {
1229 file_error(ms, 0, "name use count (%hu) exceeded",
1230 *name_count);
1231 return -1;
1232 }
1233
1234 if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1235 (uint32_t)nbytes, m) == -1)
1236 return -1;
1237
1238 if ((ms->flags & MAGIC_DEBUG) != 0) {
1239 fprintf(stderr, "mget(type=%d, flag=%x, offset=%u, o=%"
1240 SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1241 "u, il=%hu, nc=%hu)\n",
1242 m->type, m->flag, offset, o, nbytes,
1243 indir_level, *name_count);
1244 mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1245 #ifndef COMPILE_ONLY
1246 file_mdump(m);
1247 #endif
1248 }
1249
1250 if (m->flag & INDIR) {
1251 int off = m->in_offset;
1252 if (m->in_op & FILE_OPINDIRECT) {
1253 const union VALUETYPE *q = CAST(const union VALUETYPE *,
1254 ((const void *)(s + offset + off)));
1255 switch (cvt_flip(m->in_type, flip)) {
1256 case FILE_BYTE:
1257 off = q->b;
1258 break;
1259 case FILE_SHORT:
1260 off = q->h;
1261 break;
1262 case FILE_BESHORT:
1263 off = (short)((q->hs[0]<<8)|(q->hs[1]));
1264 break;
1265 case FILE_LESHORT:
1266 off = (short)((q->hs[1]<<8)|(q->hs[0]));
1267 break;
1268 case FILE_LONG:
1269 off = q->l;
1270 break;
1271 case FILE_BELONG:
1272 case FILE_BEID3:
1273 off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1274 (q->hl[2]<<8)|(q->hl[3]));
1275 break;
1276 case FILE_LEID3:
1277 case FILE_LELONG:
1278 off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1279 (q->hl[1]<<8)|(q->hl[0]));
1280 break;
1281 case FILE_MELONG:
1282 off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1283 (q->hl[3]<<8)|(q->hl[2]));
1284 break;
1285 }
1286 if ((ms->flags & MAGIC_DEBUG) != 0)
1287 fprintf(stderr, "indirect offs=%u\n", off);
1288 }
1289 switch (in_type = cvt_flip(m->in_type, flip)) {
1290 case FILE_BYTE:
1291 if (OFFSET_OOB(nbytes, offset, 1))
1292 return 0;
1293 if (off) {
1294 switch (m->in_op & FILE_OPS_MASK) {
1295 case FILE_OPAND:
1296 offset = p->b & off;
1297 break;
1298 case FILE_OPOR:
1299 offset = p->b | off;
1300 break;
1301 case FILE_OPXOR:
1302 offset = p->b ^ off;
1303 break;
1304 case FILE_OPADD:
1305 offset = p->b + off;
1306 break;
1307 case FILE_OPMINUS:
1308 offset = p->b - off;
1309 break;
1310 case FILE_OPMULTIPLY:
1311 offset = p->b * off;
1312 break;
1313 case FILE_OPDIVIDE:
1314 offset = p->b / off;
1315 break;
1316 case FILE_OPMODULO:
1317 offset = p->b % off;
1318 break;
1319 }
1320 } else
1321 offset = p->b;
1322 if (m->in_op & FILE_OPINVERSE)
1323 offset = ~offset;
1324 break;
1325 case FILE_BESHORT:
1326 if (OFFSET_OOB(nbytes, offset, 2))
1327 return 0;
1328 lhs = (p->hs[0] << 8) | p->hs[1];
1329 if (off) {
1330 switch (m->in_op & FILE_OPS_MASK) {
1331 case FILE_OPAND:
1332 offset = lhs & off;
1333 break;
1334 case FILE_OPOR:
1335 offset = lhs | off;
1336 break;
1337 case FILE_OPXOR:
1338 offset = lhs ^ off;
1339 break;
1340 case FILE_OPADD:
1341 offset = lhs + off;
1342 break;
1343 case FILE_OPMINUS:
1344 offset = lhs - off;
1345 break;
1346 case FILE_OPMULTIPLY:
1347 offset = lhs * off;
1348 break;
1349 case FILE_OPDIVIDE:
1350 offset = lhs / off;
1351 break;
1352 case FILE_OPMODULO:
1353 offset = lhs % off;
1354 break;
1355 }
1356 } else
1357 offset = lhs;
1358 if (m->in_op & FILE_OPINVERSE)
1359 offset = ~offset;
1360 break;
1361 case FILE_LESHORT:
1362 if (OFFSET_OOB(nbytes, offset, 2))
1363 return 0;
1364 lhs = (p->hs[1] << 8) | p->hs[0];
1365 if (off) {
1366 switch (m->in_op & FILE_OPS_MASK) {
1367 case FILE_OPAND:
1368 offset = lhs & off;
1369 break;
1370 case FILE_OPOR:
1371 offset = lhs | off;
1372 break;
1373 case FILE_OPXOR:
1374 offset = lhs ^ off;
1375 break;
1376 case FILE_OPADD:
1377 offset = lhs + off;
1378 break;
1379 case FILE_OPMINUS:
1380 offset = lhs - off;
1381 break;
1382 case FILE_OPMULTIPLY:
1383 offset = lhs * off;
1384 break;
1385 case FILE_OPDIVIDE:
1386 offset = lhs / off;
1387 break;
1388 case FILE_OPMODULO:
1389 offset = lhs % off;
1390 break;
1391 }
1392 } else
1393 offset = lhs;
1394 if (m->in_op & FILE_OPINVERSE)
1395 offset = ~offset;
1396 break;
1397 case FILE_SHORT:
1398 if (OFFSET_OOB(nbytes, offset, 2))
1399 return 0;
1400 if (off) {
1401 switch (m->in_op & FILE_OPS_MASK) {
1402 case FILE_OPAND:
1403 offset = p->h & off;
1404 break;
1405 case FILE_OPOR:
1406 offset = p->h | off;
1407 break;
1408 case FILE_OPXOR:
1409 offset = p->h ^ off;
1410 break;
1411 case FILE_OPADD:
1412 offset = p->h + off;
1413 break;
1414 case FILE_OPMINUS:
1415 offset = p->h - off;
1416 break;
1417 case FILE_OPMULTIPLY:
1418 offset = p->h * off;
1419 break;
1420 case FILE_OPDIVIDE:
1421 offset = p->h / off;
1422 break;
1423 case FILE_OPMODULO:
1424 offset = p->h % off;
1425 break;
1426 }
1427 }
1428 else
1429 offset = p->h;
1430 if (m->in_op & FILE_OPINVERSE)
1431 offset = ~offset;
1432 break;
1433 case FILE_BELONG:
1434 case FILE_BEID3:
1435 if (OFFSET_OOB(nbytes, offset, 4))
1436 return 0;
1437 lhs = (p->hl[0] << 24) | (p->hl[1] << 16) |
1438 (p->hl[2] << 8) | p->hl[3];
1439 if (off) {
1440 switch (m->in_op & FILE_OPS_MASK) {
1441 case FILE_OPAND:
1442 offset = lhs & off;
1443 break;
1444 case FILE_OPOR:
1445 offset = lhs | off;
1446 break;
1447 case FILE_OPXOR:
1448 offset = lhs ^ off;
1449 break;
1450 case FILE_OPADD:
1451 offset = lhs + off;
1452 break;
1453 case FILE_OPMINUS:
1454 offset = lhs - off;
1455 break;
1456 case FILE_OPMULTIPLY:
1457 offset = lhs * off;
1458 break;
1459 case FILE_OPDIVIDE:
1460 offset = lhs / off;
1461 break;
1462 case FILE_OPMODULO:
1463 offset = lhs % off;
1464 break;
1465 }
1466 } else
1467 offset = lhs;
1468 if (m->in_op & FILE_OPINVERSE)
1469 offset = ~offset;
1470 break;
1471 case FILE_LELONG:
1472 case FILE_LEID3:
1473 if (OFFSET_OOB(nbytes, offset, 4))
1474 return 0;
1475 lhs = (p->hl[3] << 24) | (p->hl[2] << 16) |
1476 (p->hl[1] << 8) | p->hl[0];
1477 if (off) {
1478 switch (m->in_op & FILE_OPS_MASK) {
1479 case FILE_OPAND:
1480 offset = lhs & off;
1481 break;
1482 case FILE_OPOR:
1483 offset = lhs | off;
1484 break;
1485 case FILE_OPXOR:
1486 offset = lhs ^ off;
1487 break;
1488 case FILE_OPADD:
1489 offset = lhs + off;
1490 break;
1491 case FILE_OPMINUS:
1492 offset = lhs - off;
1493 break;
1494 case FILE_OPMULTIPLY:
1495 offset = lhs * off;
1496 break;
1497 case FILE_OPDIVIDE:
1498 offset = lhs / off;
1499 break;
1500 case FILE_OPMODULO:
1501 offset = lhs % off;
1502 break;
1503 }
1504 } else
1505 offset = lhs;
1506 if (m->in_op & FILE_OPINVERSE)
1507 offset = ~offset;
1508 break;
1509 case FILE_MELONG:
1510 if (OFFSET_OOB(nbytes, offset, 4))
1511 return 0;
1512 lhs = (p->hl[1] << 24) | (p->hl[0] << 16) |
1513 (p->hl[3] << 8) | p->hl[2];
1514 if (off) {
1515 switch (m->in_op & FILE_OPS_MASK) {
1516 case FILE_OPAND:
1517 offset = lhs & off;
1518 break;
1519 case FILE_OPOR:
1520 offset = lhs | off;
1521 break;
1522 case FILE_OPXOR:
1523 offset = lhs ^ off;
1524 break;
1525 case FILE_OPADD:
1526 offset = lhs + off;
1527 break;
1528 case FILE_OPMINUS:
1529 offset = lhs - off;
1530 break;
1531 case FILE_OPMULTIPLY:
1532 offset = lhs * off;
1533 break;
1534 case FILE_OPDIVIDE:
1535 offset = lhs / off;
1536 break;
1537 case FILE_OPMODULO:
1538 offset = lhs % off;
1539 break;
1540 }
1541 } else
1542 offset = lhs;
1543 if (m->in_op & FILE_OPINVERSE)
1544 offset = ~offset;
1545 break;
1546 case FILE_LONG:
1547 if (OFFSET_OOB(nbytes, offset, 4))
1548 return 0;
1549 if (off) {
1550 switch (m->in_op & FILE_OPS_MASK) {
1551 case FILE_OPAND:
1552 offset = p->l & off;
1553 break;
1554 case FILE_OPOR:
1555 offset = p->l | off;
1556 break;
1557 case FILE_OPXOR:
1558 offset = p->l ^ off;
1559 break;
1560 case FILE_OPADD:
1561 offset = p->l + off;
1562 break;
1563 case FILE_OPMINUS:
1564 offset = p->l - off;
1565 break;
1566 case FILE_OPMULTIPLY:
1567 offset = p->l * off;
1568 break;
1569 case FILE_OPDIVIDE:
1570 offset = p->l / off;
1571 break;
1572 case FILE_OPMODULO:
1573 offset = p->l % off;
1574 break;
1575 }
1576 } else
1577 offset = p->l;
1578 if (m->in_op & FILE_OPINVERSE)
1579 offset = ~offset;
1580 break;
1581 default:
1582 break;
1583 }
1584
1585 switch (in_type) {
1586 case FILE_LEID3:
1587 case FILE_BEID3:
1588 offset = ((((offset >> 0) & 0x7f) << 0) |
1589 (((offset >> 8) & 0x7f) << 7) |
1590 (((offset >> 16) & 0x7f) << 14) |
1591 (((offset >> 24) & 0x7f) << 21)) + 10;
1592 break;
1593 default:
1594 break;
1595 }
1596
1597 if (m->flag & INDIROFFADD) {
1598 offset += ms->c.li[cont_level-1].off;
1599 if (offset == 0) {
1600 if ((ms->flags & MAGIC_DEBUG) != 0)
1601 fprintf(stderr,
1602 "indirect *zero* offset\n");
1603 return 0;
1604 }
1605 if ((ms->flags & MAGIC_DEBUG) != 0)
1606 fprintf(stderr, "indirect +offs=%u\n", offset);
1607 }
1608 if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1609 return -1;
1610 ms->offset = offset;
1611
1612 if ((ms->flags & MAGIC_DEBUG) != 0) {
1613 mdebug(offset, (char *)(void *)p,
1614 sizeof(union VALUETYPE));
1615 #ifndef COMPILE_ONLY
1616 file_mdump(m);
1617 #endif
1618 }
1619 }
1620
1621 /* Verify we have enough data to match magic type */
1622 switch (m->type) {
1623 case FILE_BYTE:
1624 if (OFFSET_OOB(nbytes, offset, 1))
1625 return 0;
1626 break;
1627
1628 case FILE_SHORT:
1629 case FILE_BESHORT:
1630 case FILE_LESHORT:
1631 if (OFFSET_OOB(nbytes, offset, 2))
1632 return 0;
1633 break;
1634
1635 case FILE_LONG:
1636 case FILE_BELONG:
1637 case FILE_LELONG:
1638 case FILE_MELONG:
1639 case FILE_DATE:
1640 case FILE_BEDATE:
1641 case FILE_LEDATE:
1642 case FILE_MEDATE:
1643 case FILE_LDATE:
1644 case FILE_BELDATE:
1645 case FILE_LELDATE:
1646 case FILE_MELDATE:
1647 case FILE_FLOAT:
1648 case FILE_BEFLOAT:
1649 case FILE_LEFLOAT:
1650 if (OFFSET_OOB(nbytes, offset, 4))
1651 return 0;
1652 break;
1653
1654 case FILE_DOUBLE:
1655 case FILE_BEDOUBLE:
1656 case FILE_LEDOUBLE:
1657 if (OFFSET_OOB(nbytes, offset, 8))
1658 return 0;
1659 break;
1660
1661 case FILE_STRING:
1662 case FILE_PSTRING:
1663 case FILE_SEARCH:
1664 if (OFFSET_OOB(nbytes, offset, m->vallen))
1665 return 0;
1666 break;
1667
1668 case FILE_REGEX:
1669 if (nbytes < offset)
1670 return 0;
1671 break;
1672
1673 case FILE_INDIRECT:
1674 if (m->str_flags & INDIRECT_RELATIVE)
1675 offset += CAST(uint32_t, o);
1676 if (offset == 0)
1677 return 0;
1678
1679 if (nbytes < offset)
1680 return 0;
1681
1682 if ((pb = file_push_buffer(ms)) == NULL)
1683 return -1;
1684
1685 rv = file_softmagic(ms, s + offset, nbytes - offset,
1686 indir_level + 1, name_count, BINTEST, text);
1687
1688 if ((ms->flags & MAGIC_DEBUG) != 0)
1689 fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1690
1691 rbuf = file_pop_buffer(ms, pb);
1692 if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1693 return -1;
1694
1695 if (rv == 1) {
1696 if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1697 file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1698 free(rbuf);
1699 return -1;
1700 }
1701 if (file_printf(ms, "%s", rbuf) == -1) {
1702 free(rbuf);
1703 return -1;
1704 }
1705 }
1706 free(rbuf);
1707 return rv;
1708
1709 case FILE_USE:
1710 if (nbytes < offset)
1711 return 0;
1712 rbuf = m->value.s;
1713 if (*rbuf == '^') {
1714 rbuf++;
1715 flip = !flip;
1716 }
1717 if (file_magicfind(ms, rbuf, &ml) == -1) {
1718 file_error(ms, 0, "cannot find entry `%s'", rbuf);
1719 return -1;
1720 }
1721 (*name_count)++;
1722 oneed_separator = *need_separator;
1723 if (m->flag & NOSPACE)
1724 *need_separator = 0;
1725 rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1726 mode, text, flip, indir_level, name_count,
1727 printed_something, need_separator, returnval);
1728 if (rv != 1)
1729 *need_separator = oneed_separator;
1730 return rv;
1731
1732 case FILE_NAME:
1733 if (file_printf(ms, "%s", m->desc) == -1)
1734 return -1;
1735 return 1;
1736 case FILE_DEFAULT: /* nothing to check */
1737 case FILE_CLEAR:
1738 default:
1739 break;
1740 }
1741 if (!mconvert(ms, m, flip))
1742 return 0;
1743 return 1;
1744 }
1745
1746 private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,uint32_t flags)1747 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1748 {
1749 /*
1750 * Convert the source args to unsigned here so that (1) the
1751 * compare will be unsigned as it is in strncmp() and (2) so
1752 * the ctype functions will work correctly without extra
1753 * casting.
1754 */
1755 const unsigned char *a = (const unsigned char *)s1;
1756 const unsigned char *b = (const unsigned char *)s2;
1757 uint64_t v;
1758
1759 /*
1760 * What we want here is v = strncmp(s1, s2, len),
1761 * but ignoring any nulls.
1762 */
1763 v = 0;
1764 if (0L == flags) { /* normal string: do it fast */
1765 while (len-- > 0)
1766 if ((v = *b++ - *a++) != '\0')
1767 break;
1768 }
1769 else { /* combine the others */
1770 while (len-- > 0) {
1771 if ((flags & STRING_IGNORE_LOWERCASE) &&
1772 islower(*a)) {
1773 if ((v = tolower(*b++) - *a++) != '\0')
1774 break;
1775 }
1776 else if ((flags & STRING_IGNORE_UPPERCASE) &&
1777 isupper(*a)) {
1778 if ((v = toupper(*b++) - *a++) != '\0')
1779 break;
1780 }
1781 else if ((flags & STRING_COMPACT_WHITESPACE) &&
1782 isspace(*a)) {
1783 a++;
1784 if (isspace(*b++)) {
1785 if (!isspace(*a))
1786 while (isspace(*b))
1787 b++;
1788 }
1789 else {
1790 v = 1;
1791 break;
1792 }
1793 }
1794 else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1795 isspace(*a)) {
1796 a++;
1797 while (isspace(*b))
1798 b++;
1799 }
1800 else {
1801 if ((v = *b++ - *a++) != '\0')
1802 break;
1803 }
1804 }
1805 }
1806 return v;
1807 }
1808
1809 private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,uint32_t flags)1810 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1811 {
1812 /*
1813 * XXX - The 16-bit string compare probably needs to be done
1814 * differently, especially if the flags are to be supported.
1815 * At the moment, I am unsure.
1816 */
1817 flags = 0;
1818 return file_strncmp(a, b, len, flags);
1819 }
1820
1821 private int
magiccheck(struct magic_set * ms,struct magic * m)1822 magiccheck(struct magic_set *ms, struct magic *m)
1823 {
1824 uint64_t l = m->value.q;
1825 uint64_t v;
1826 float fl, fv;
1827 double dl, dv;
1828 int matched;
1829 union VALUETYPE *p = &ms->ms_value;
1830
1831 switch (m->type) {
1832 case FILE_BYTE:
1833 v = p->b;
1834 break;
1835
1836 case FILE_SHORT:
1837 case FILE_BESHORT:
1838 case FILE_LESHORT:
1839 v = p->h;
1840 break;
1841
1842 case FILE_LONG:
1843 case FILE_BELONG:
1844 case FILE_LELONG:
1845 case FILE_MELONG:
1846 case FILE_DATE:
1847 case FILE_BEDATE:
1848 case FILE_LEDATE:
1849 case FILE_MEDATE:
1850 case FILE_LDATE:
1851 case FILE_BELDATE:
1852 case FILE_LELDATE:
1853 case FILE_MELDATE:
1854 v = p->l;
1855 break;
1856
1857 case FILE_QUAD:
1858 case FILE_LEQUAD:
1859 case FILE_BEQUAD:
1860 case FILE_QDATE:
1861 case FILE_BEQDATE:
1862 case FILE_LEQDATE:
1863 case FILE_QLDATE:
1864 case FILE_BEQLDATE:
1865 case FILE_LEQLDATE:
1866 case FILE_QWDATE:
1867 case FILE_BEQWDATE:
1868 case FILE_LEQWDATE:
1869 v = p->q;
1870 break;
1871
1872 case FILE_FLOAT:
1873 case FILE_BEFLOAT:
1874 case FILE_LEFLOAT:
1875 fl = m->value.f;
1876 fv = p->f;
1877 switch (m->reln) {
1878 case 'x':
1879 matched = 1;
1880 break;
1881
1882 case '!':
1883 matched = fv != fl;
1884 break;
1885
1886 case '=':
1887 matched = fv == fl;
1888 break;
1889
1890 case '>':
1891 matched = fv > fl;
1892 break;
1893
1894 case '<':
1895 matched = fv < fl;
1896 break;
1897
1898 default:
1899 file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1900 m->reln);
1901 return -1;
1902 }
1903 return matched;
1904
1905 case FILE_DOUBLE:
1906 case FILE_BEDOUBLE:
1907 case FILE_LEDOUBLE:
1908 dl = m->value.d;
1909 dv = p->d;
1910 switch (m->reln) {
1911 case 'x':
1912 matched = 1;
1913 break;
1914
1915 case '!':
1916 matched = dv != dl;
1917 break;
1918
1919 case '=':
1920 matched = dv == dl;
1921 break;
1922
1923 case '>':
1924 matched = dv > dl;
1925 break;
1926
1927 case '<':
1928 matched = dv < dl;
1929 break;
1930
1931 default:
1932 file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1933 return -1;
1934 }
1935 return matched;
1936
1937 case FILE_DEFAULT:
1938 case FILE_CLEAR:
1939 l = 0;
1940 v = 0;
1941 break;
1942
1943 case FILE_STRING:
1944 case FILE_PSTRING:
1945 l = 0;
1946 v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1947 break;
1948
1949 case FILE_BESTRING16:
1950 case FILE_LESTRING16:
1951 l = 0;
1952 v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1953 break;
1954
1955 case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1956 size_t slen;
1957 size_t idx;
1958
1959 if (ms->search.s == NULL)
1960 return 0;
1961
1962 slen = MIN(m->vallen, sizeof(m->value.s));
1963 l = 0;
1964 v = 0;
1965
1966 for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1967 if (slen + idx > ms->search.s_len)
1968 break;
1969
1970 v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1971 m->str_flags);
1972 if (v == 0) { /* found match */
1973 ms->search.offset += idx;
1974 break;
1975 }
1976 }
1977 break;
1978 }
1979 case FILE_REGEX: {
1980 int rc;
1981 file_regex_t rx;
1982 const char *search;
1983
1984 if (ms->search.s == NULL)
1985 return 0;
1986
1987 l = 0;
1988 rc = file_regcomp(&rx, m->value.s,
1989 REG_EXTENDED|REG_NEWLINE|
1990 ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1991 if (rc) {
1992 file_regerror(&rx, rc, ms);
1993 v = (uint64_t)-1;
1994 } else {
1995 regmatch_t pmatch[1];
1996 size_t slen = ms->search.s_len;
1997 #ifndef REG_STARTEND
1998 #define REG_STARTEND 0
1999 char *copy;
2000 if (slen != 0) {
2001 copy = malloc(slen);
2002 if (copy == NULL) {
2003 file_error(ms, errno,
2004 "can't allocate %" SIZE_T_FORMAT "u bytes",
2005 slen);
2006 return -1;
2007 }
2008 memcpy(copy, ms->search.s, slen);
2009 copy[--slen] = '\0';
2010 search = copy;
2011 } else {
2012 search = ms->search.s;
2013 copy = NULL;
2014 }
2015 #else
2016 search = ms->search.s;
2017 pmatch[0].rm_so = 0;
2018 pmatch[0].rm_eo = slen;
2019 #endif
2020 rc = file_regexec(&rx, (const char *)search,
2021 1, pmatch, REG_STARTEND);
2022 #if REG_STARTEND == 0
2023 free(copy);
2024 #endif
2025 switch (rc) {
2026 case 0:
2027 ms->search.s += (int)pmatch[0].rm_so;
2028 ms->search.offset += (size_t)pmatch[0].rm_so;
2029 ms->search.rm_len =
2030 (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
2031 v = 0;
2032 break;
2033
2034 case REG_NOMATCH:
2035 v = 1;
2036 break;
2037
2038 default:
2039 file_regerror(&rx, rc, ms);
2040 v = (uint64_t)-1;
2041 break;
2042 }
2043 }
2044 file_regfree(&rx);
2045 if (v == (uint64_t)-1)
2046 return -1;
2047 break;
2048 }
2049 case FILE_INDIRECT:
2050 case FILE_USE:
2051 case FILE_NAME:
2052 return 1;
2053 default:
2054 file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2055 return -1;
2056 }
2057
2058 v = file_signextend(ms, m, v);
2059
2060 switch (m->reln) {
2061 case 'x':
2062 if ((ms->flags & MAGIC_DEBUG) != 0)
2063 (void) fprintf(stderr, "%" INT64_T_FORMAT
2064 "u == *any* = 1\n", (unsigned long long)v);
2065 matched = 1;
2066 break;
2067
2068 case '!':
2069 matched = v != l;
2070 if ((ms->flags & MAGIC_DEBUG) != 0)
2071 (void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2072 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2073 (unsigned long long)l, matched);
2074 break;
2075
2076 case '=':
2077 matched = v == l;
2078 if ((ms->flags & MAGIC_DEBUG) != 0)
2079 (void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2080 INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
2081 (unsigned long long)l, matched);
2082 break;
2083
2084 case '>':
2085 if (m->flag & UNSIGNED) {
2086 matched = v > l;
2087 if ((ms->flags & MAGIC_DEBUG) != 0)
2088 (void) fprintf(stderr, "%" INT64_T_FORMAT
2089 "u > %" INT64_T_FORMAT "u = %d\n",
2090 (unsigned long long)v,
2091 (unsigned long long)l, matched);
2092 }
2093 else {
2094 matched = (int64_t) v > (int64_t) l;
2095 if ((ms->flags & MAGIC_DEBUG) != 0)
2096 (void) fprintf(stderr, "%" INT64_T_FORMAT
2097 "d > %" INT64_T_FORMAT "d = %d\n",
2098 (long long)v, (long long)l, matched);
2099 }
2100 break;
2101
2102 case '<':
2103 if (m->flag & UNSIGNED) {
2104 matched = v < l;
2105 if ((ms->flags & MAGIC_DEBUG) != 0)
2106 (void) fprintf(stderr, "%" INT64_T_FORMAT
2107 "u < %" INT64_T_FORMAT "u = %d\n",
2108 (unsigned long long)v,
2109 (unsigned long long)l, matched);
2110 }
2111 else {
2112 matched = (int64_t) v < (int64_t) l;
2113 if ((ms->flags & MAGIC_DEBUG) != 0)
2114 (void) fprintf(stderr, "%" INT64_T_FORMAT
2115 "d < %" INT64_T_FORMAT "d = %d\n",
2116 (long long)v, (long long)l, matched);
2117 }
2118 break;
2119
2120 case '&':
2121 matched = (v & l) == l;
2122 if ((ms->flags & MAGIC_DEBUG) != 0)
2123 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2124 INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2125 "x) = %d\n", (unsigned long long)v,
2126 (unsigned long long)l, (unsigned long long)l,
2127 matched);
2128 break;
2129
2130 case '^':
2131 matched = (v & l) != l;
2132 if ((ms->flags & MAGIC_DEBUG) != 0)
2133 (void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2134 INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2135 "x) = %d\n", (unsigned long long)v,
2136 (unsigned long long)l, (unsigned long long)l,
2137 matched);
2138 break;
2139
2140 default:
2141 file_magerror(ms, "cannot happen: invalid relation `%c'",
2142 m->reln);
2143 return -1;
2144 }
2145
2146 return matched;
2147 }
2148
2149 private int
handle_annotation(struct magic_set * ms,struct magic * m)2150 handle_annotation(struct magic_set *ms, struct magic *m)
2151 {
2152 if (ms->flags & MAGIC_APPLE) {
2153 if (file_printf(ms, "%.8s", m->apple) == -1)
2154 return -1;
2155 return 1;
2156 }
2157 if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2158 if (file_printf(ms, "%s", m->mimetype) == -1)
2159 return -1;
2160 return 1;
2161 }
2162 return 0;
2163 }
2164
2165 private int
print_sep(struct magic_set * ms,int firstline)2166 print_sep(struct magic_set *ms, int firstline)
2167 {
2168 if (ms->flags & MAGIC_MIME)
2169 return 0;
2170 if (firstline)
2171 return 0;
2172 /*
2173 * we found another match
2174 * put a newline and '-' to do some simple formatting
2175 */
2176 return file_printf(ms, "\n- ");
2177 }
2178