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