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