xref: /netbsd-src/external/bsd/file/dist/src/softmagic.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1 /*	$NetBSD: softmagic.c,v 1.6 2012/04/07 17:30:56 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.6 2012/04/07 17:30:56 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 	int rv;
1032 	char *sbuf, *rbuf;
1033 	union VALUETYPE *p = &ms->ms_value;
1034 
1035 	if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
1036 		return -1;
1037 
1038 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1039 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1040 #ifndef COMPILE_ONLY
1041 		file_mdump(m);
1042 #endif
1043 	}
1044 
1045 	if (m->flag & INDIR) {
1046 		int off = m->in_offset;
1047 		if (m->in_op & FILE_OPINDIRECT) {
1048 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1049 			    ((const void *)(s + offset + off)));
1050 			switch (m->in_type) {
1051 			case FILE_BYTE:
1052 				off = q->b;
1053 				break;
1054 			case FILE_SHORT:
1055 				off = q->h;
1056 				break;
1057 			case FILE_BESHORT:
1058 				off = (short)((q->hs[0]<<8)|(q->hs[1]));
1059 				break;
1060 			case FILE_LESHORT:
1061 				off = (short)((q->hs[1]<<8)|(q->hs[0]));
1062 				break;
1063 			case FILE_LONG:
1064 				off = q->l;
1065 				break;
1066 			case FILE_BELONG:
1067 			case FILE_BEID3:
1068 				off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1069 						 (q->hl[2]<<8)|(q->hl[3]));
1070 				break;
1071 			case FILE_LEID3:
1072 			case FILE_LELONG:
1073 				off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1074 						 (q->hl[1]<<8)|(q->hl[0]));
1075 				break;
1076 			case FILE_MELONG:
1077 				off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1078 						 (q->hl[3]<<8)|(q->hl[2]));
1079 				break;
1080 			}
1081 			if ((ms->flags & MAGIC_DEBUG) != 0)
1082 				fprintf(stderr, "indirect offs=%u\n", off);
1083 		}
1084 		switch (m->in_type) {
1085 		case FILE_BYTE:
1086 			if (nbytes < (offset + 1))
1087 				return 0;
1088 			if (off) {
1089 				switch (m->in_op & FILE_OPS_MASK) {
1090 				case FILE_OPAND:
1091 					offset = p->b & off;
1092 					break;
1093 				case FILE_OPOR:
1094 					offset = p->b | off;
1095 					break;
1096 				case FILE_OPXOR:
1097 					offset = p->b ^ off;
1098 					break;
1099 				case FILE_OPADD:
1100 					offset = p->b + off;
1101 					break;
1102 				case FILE_OPMINUS:
1103 					offset = p->b - off;
1104 					break;
1105 				case FILE_OPMULTIPLY:
1106 					offset = p->b * off;
1107 					break;
1108 				case FILE_OPDIVIDE:
1109 					offset = p->b / off;
1110 					break;
1111 				case FILE_OPMODULO:
1112 					offset = p->b % off;
1113 					break;
1114 				}
1115 			} else
1116 				offset = p->b;
1117 			if (m->in_op & FILE_OPINVERSE)
1118 				offset = ~offset;
1119 			break;
1120 		case FILE_BESHORT:
1121 			if (nbytes < (offset + 2))
1122 				return 0;
1123 			if (off) {
1124 				switch (m->in_op & FILE_OPS_MASK) {
1125 				case FILE_OPAND:
1126 					offset = (short)((p->hs[0]<<8)|
1127 							 (p->hs[1])) &
1128 						 off;
1129 					break;
1130 				case FILE_OPOR:
1131 					offset = (short)((p->hs[0]<<8)|
1132 							 (p->hs[1])) |
1133 						 off;
1134 					break;
1135 				case FILE_OPXOR:
1136 					offset = (short)((p->hs[0]<<8)|
1137 							 (p->hs[1])) ^
1138 						 off;
1139 					break;
1140 				case FILE_OPADD:
1141 					offset = (short)((p->hs[0]<<8)|
1142 							 (p->hs[1])) +
1143 						 off;
1144 					break;
1145 				case FILE_OPMINUS:
1146 					offset = (short)((p->hs[0]<<8)|
1147 							 (p->hs[1])) -
1148 						 off;
1149 					break;
1150 				case FILE_OPMULTIPLY:
1151 					offset = (short)((p->hs[0]<<8)|
1152 							 (p->hs[1])) *
1153 						 off;
1154 					break;
1155 				case FILE_OPDIVIDE:
1156 					offset = (short)((p->hs[0]<<8)|
1157 							 (p->hs[1])) /
1158 						 off;
1159 					break;
1160 				case FILE_OPMODULO:
1161 					offset = (short)((p->hs[0]<<8)|
1162 							 (p->hs[1])) %
1163 						 off;
1164 					break;
1165 				}
1166 			} else
1167 				offset = (short)((p->hs[0]<<8)|
1168 						 (p->hs[1]));
1169 			if (m->in_op & FILE_OPINVERSE)
1170 				offset = ~offset;
1171 			break;
1172 		case FILE_LESHORT:
1173 			if (nbytes < (offset + 2))
1174 				return 0;
1175 			if (off) {
1176 				switch (m->in_op & FILE_OPS_MASK) {
1177 				case FILE_OPAND:
1178 					offset = (short)((p->hs[1]<<8)|
1179 							 (p->hs[0])) &
1180 						 off;
1181 					break;
1182 				case FILE_OPOR:
1183 					offset = (short)((p->hs[1]<<8)|
1184 							 (p->hs[0])) |
1185 						 off;
1186 					break;
1187 				case FILE_OPXOR:
1188 					offset = (short)((p->hs[1]<<8)|
1189 							 (p->hs[0])) ^
1190 						 off;
1191 					break;
1192 				case FILE_OPADD:
1193 					offset = (short)((p->hs[1]<<8)|
1194 							 (p->hs[0])) +
1195 						 off;
1196 					break;
1197 				case FILE_OPMINUS:
1198 					offset = (short)((p->hs[1]<<8)|
1199 							 (p->hs[0])) -
1200 						 off;
1201 					break;
1202 				case FILE_OPMULTIPLY:
1203 					offset = (short)((p->hs[1]<<8)|
1204 							 (p->hs[0])) *
1205 						 off;
1206 					break;
1207 				case FILE_OPDIVIDE:
1208 					offset = (short)((p->hs[1]<<8)|
1209 							 (p->hs[0])) /
1210 						 off;
1211 					break;
1212 				case FILE_OPMODULO:
1213 					offset = (short)((p->hs[1]<<8)|
1214 							 (p->hs[0])) %
1215 						 off;
1216 					break;
1217 				}
1218 			} else
1219 				offset = (short)((p->hs[1]<<8)|
1220 						 (p->hs[0]));
1221 			if (m->in_op & FILE_OPINVERSE)
1222 				offset = ~offset;
1223 			break;
1224 		case FILE_SHORT:
1225 			if (nbytes < (offset + 2))
1226 				return 0;
1227 			if (off) {
1228 				switch (m->in_op & FILE_OPS_MASK) {
1229 				case FILE_OPAND:
1230 					offset = p->h & off;
1231 					break;
1232 				case FILE_OPOR:
1233 					offset = p->h | off;
1234 					break;
1235 				case FILE_OPXOR:
1236 					offset = p->h ^ off;
1237 					break;
1238 				case FILE_OPADD:
1239 					offset = p->h + off;
1240 					break;
1241 				case FILE_OPMINUS:
1242 					offset = p->h - off;
1243 					break;
1244 				case FILE_OPMULTIPLY:
1245 					offset = p->h * off;
1246 					break;
1247 				case FILE_OPDIVIDE:
1248 					offset = p->h / off;
1249 					break;
1250 				case FILE_OPMODULO:
1251 					offset = p->h % off;
1252 					break;
1253 				}
1254 			}
1255 			else
1256 				offset = p->h;
1257 			if (m->in_op & FILE_OPINVERSE)
1258 				offset = ~offset;
1259 			break;
1260 		case FILE_BELONG:
1261 		case FILE_BEID3:
1262 			if (nbytes < (offset + 4))
1263 				return 0;
1264 			if (off) {
1265 				switch (m->in_op & FILE_OPS_MASK) {
1266 				case FILE_OPAND:
1267 					offset = (int32_t)((p->hl[0]<<24)|
1268 							 (p->hl[1]<<16)|
1269 							 (p->hl[2]<<8)|
1270 							 (p->hl[3])) &
1271 						 off;
1272 					break;
1273 				case FILE_OPOR:
1274 					offset = (int32_t)((p->hl[0]<<24)|
1275 							 (p->hl[1]<<16)|
1276 							 (p->hl[2]<<8)|
1277 							 (p->hl[3])) |
1278 						 off;
1279 					break;
1280 				case FILE_OPXOR:
1281 					offset = (int32_t)((p->hl[0]<<24)|
1282 							 (p->hl[1]<<16)|
1283 							 (p->hl[2]<<8)|
1284 							 (p->hl[3])) ^
1285 						 off;
1286 					break;
1287 				case FILE_OPADD:
1288 					offset = (int32_t)((p->hl[0]<<24)|
1289 							 (p->hl[1]<<16)|
1290 							 (p->hl[2]<<8)|
1291 							 (p->hl[3])) +
1292 						 off;
1293 					break;
1294 				case FILE_OPMINUS:
1295 					offset = (int32_t)((p->hl[0]<<24)|
1296 							 (p->hl[1]<<16)|
1297 							 (p->hl[2]<<8)|
1298 							 (p->hl[3])) -
1299 						 off;
1300 					break;
1301 				case FILE_OPMULTIPLY:
1302 					offset = (int32_t)((p->hl[0]<<24)|
1303 							 (p->hl[1]<<16)|
1304 							 (p->hl[2]<<8)|
1305 							 (p->hl[3])) *
1306 						 off;
1307 					break;
1308 				case FILE_OPDIVIDE:
1309 					offset = (int32_t)((p->hl[0]<<24)|
1310 							 (p->hl[1]<<16)|
1311 							 (p->hl[2]<<8)|
1312 							 (p->hl[3])) /
1313 						 off;
1314 					break;
1315 				case FILE_OPMODULO:
1316 					offset = (int32_t)((p->hl[0]<<24)|
1317 							 (p->hl[1]<<16)|
1318 							 (p->hl[2]<<8)|
1319 							 (p->hl[3])) %
1320 						 off;
1321 					break;
1322 				}
1323 			} else
1324 				offset = (int32_t)((p->hl[0]<<24)|
1325 						 (p->hl[1]<<16)|
1326 						 (p->hl[2]<<8)|
1327 						 (p->hl[3]));
1328 			if (m->in_op & FILE_OPINVERSE)
1329 				offset = ~offset;
1330 			break;
1331 		case FILE_LELONG:
1332 		case FILE_LEID3:
1333 			if (nbytes < (offset + 4))
1334 				return 0;
1335 			if (off) {
1336 				switch (m->in_op & FILE_OPS_MASK) {
1337 				case FILE_OPAND:
1338 					offset = (int32_t)((p->hl[3]<<24)|
1339 							 (p->hl[2]<<16)|
1340 							 (p->hl[1]<<8)|
1341 							 (p->hl[0])) &
1342 						 off;
1343 					break;
1344 				case FILE_OPOR:
1345 					offset = (int32_t)((p->hl[3]<<24)|
1346 							 (p->hl[2]<<16)|
1347 							 (p->hl[1]<<8)|
1348 							 (p->hl[0])) |
1349 						 off;
1350 					break;
1351 				case FILE_OPXOR:
1352 					offset = (int32_t)((p->hl[3]<<24)|
1353 							 (p->hl[2]<<16)|
1354 							 (p->hl[1]<<8)|
1355 							 (p->hl[0])) ^
1356 						 off;
1357 					break;
1358 				case FILE_OPADD:
1359 					offset = (int32_t)((p->hl[3]<<24)|
1360 							 (p->hl[2]<<16)|
1361 							 (p->hl[1]<<8)|
1362 							 (p->hl[0])) +
1363 						 off;
1364 					break;
1365 				case FILE_OPMINUS:
1366 					offset = (int32_t)((p->hl[3]<<24)|
1367 							 (p->hl[2]<<16)|
1368 							 (p->hl[1]<<8)|
1369 							 (p->hl[0])) -
1370 						 off;
1371 					break;
1372 				case FILE_OPMULTIPLY:
1373 					offset = (int32_t)((p->hl[3]<<24)|
1374 							 (p->hl[2]<<16)|
1375 							 (p->hl[1]<<8)|
1376 							 (p->hl[0])) *
1377 						 off;
1378 					break;
1379 				case FILE_OPDIVIDE:
1380 					offset = (int32_t)((p->hl[3]<<24)|
1381 							 (p->hl[2]<<16)|
1382 							 (p->hl[1]<<8)|
1383 							 (p->hl[0])) /
1384 						 off;
1385 					break;
1386 				case FILE_OPMODULO:
1387 					offset = (int32_t)((p->hl[3]<<24)|
1388 							 (p->hl[2]<<16)|
1389 							 (p->hl[1]<<8)|
1390 							 (p->hl[0])) %
1391 						 off;
1392 					break;
1393 				}
1394 			} else
1395 				offset = (int32_t)((p->hl[3]<<24)|
1396 						 (p->hl[2]<<16)|
1397 						 (p->hl[1]<<8)|
1398 						 (p->hl[0]));
1399 			if (m->in_op & FILE_OPINVERSE)
1400 				offset = ~offset;
1401 			break;
1402 		case FILE_MELONG:
1403 			if (nbytes < (offset + 4))
1404 				return 0;
1405 			if (off) {
1406 				switch (m->in_op & FILE_OPS_MASK) {
1407 				case FILE_OPAND:
1408 					offset = (int32_t)((p->hl[1]<<24)|
1409 							 (p->hl[0]<<16)|
1410 							 (p->hl[3]<<8)|
1411 							 (p->hl[2])) &
1412 						 off;
1413 					break;
1414 				case FILE_OPOR:
1415 					offset = (int32_t)((p->hl[1]<<24)|
1416 							 (p->hl[0]<<16)|
1417 							 (p->hl[3]<<8)|
1418 							 (p->hl[2])) |
1419 						 off;
1420 					break;
1421 				case FILE_OPXOR:
1422 					offset = (int32_t)((p->hl[1]<<24)|
1423 							 (p->hl[0]<<16)|
1424 							 (p->hl[3]<<8)|
1425 							 (p->hl[2])) ^
1426 						 off;
1427 					break;
1428 				case FILE_OPADD:
1429 					offset = (int32_t)((p->hl[1]<<24)|
1430 							 (p->hl[0]<<16)|
1431 							 (p->hl[3]<<8)|
1432 							 (p->hl[2])) +
1433 						 off;
1434 					break;
1435 				case FILE_OPMINUS:
1436 					offset = (int32_t)((p->hl[1]<<24)|
1437 							 (p->hl[0]<<16)|
1438 							 (p->hl[3]<<8)|
1439 							 (p->hl[2])) -
1440 						 off;
1441 					break;
1442 				case FILE_OPMULTIPLY:
1443 					offset = (int32_t)((p->hl[1]<<24)|
1444 							 (p->hl[0]<<16)|
1445 							 (p->hl[3]<<8)|
1446 							 (p->hl[2])) *
1447 						 off;
1448 					break;
1449 				case FILE_OPDIVIDE:
1450 					offset = (int32_t)((p->hl[1]<<24)|
1451 							 (p->hl[0]<<16)|
1452 							 (p->hl[3]<<8)|
1453 							 (p->hl[2])) /
1454 						 off;
1455 					break;
1456 				case FILE_OPMODULO:
1457 					offset = (int32_t)((p->hl[1]<<24)|
1458 							 (p->hl[0]<<16)|
1459 							 (p->hl[3]<<8)|
1460 							 (p->hl[2])) %
1461 						 off;
1462 					break;
1463 				}
1464 			} else
1465 				offset = (int32_t)((p->hl[1]<<24)|
1466 						 (p->hl[0]<<16)|
1467 						 (p->hl[3]<<8)|
1468 						 (p->hl[2]));
1469 			if (m->in_op & FILE_OPINVERSE)
1470 				offset = ~offset;
1471 			break;
1472 		case FILE_LONG:
1473 			if (nbytes < (offset + 4))
1474 				return 0;
1475 			if (off) {
1476 				switch (m->in_op & FILE_OPS_MASK) {
1477 				case FILE_OPAND:
1478 					offset = p->l & off;
1479 					break;
1480 				case FILE_OPOR:
1481 					offset = p->l | off;
1482 					break;
1483 				case FILE_OPXOR:
1484 					offset = p->l ^ off;
1485 					break;
1486 				case FILE_OPADD:
1487 					offset = p->l + off;
1488 					break;
1489 				case FILE_OPMINUS:
1490 					offset = p->l - off;
1491 					break;
1492 				case FILE_OPMULTIPLY:
1493 					offset = p->l * off;
1494 					break;
1495 				case FILE_OPDIVIDE:
1496 					offset = p->l / off;
1497 					break;
1498 				case FILE_OPMODULO:
1499 					offset = p->l % off;
1500 					break;
1501 				}
1502 			} else
1503 				offset = p->l;
1504 			if (m->in_op & FILE_OPINVERSE)
1505 				offset = ~offset;
1506 			break;
1507 		}
1508 
1509 		switch (m->in_type) {
1510 		case FILE_LEID3:
1511 		case FILE_BEID3:
1512 			offset = ((((offset >>  0) & 0x7f) <<  0) |
1513 				 (((offset >>  8) & 0x7f) <<  7) |
1514 				 (((offset >> 16) & 0x7f) << 14) |
1515 				 (((offset >> 24) & 0x7f) << 21)) + 10;
1516 			break;
1517 		default:
1518 			break;
1519 		}
1520 
1521 		if (m->flag & INDIROFFADD) {
1522 			offset += ms->c.li[cont_level-1].off;
1523 			if ((ms->flags & MAGIC_DEBUG) != 0)
1524 				fprintf(stderr, "indirect +offs=%u\n", offset);
1525 		}
1526 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
1527 			return -1;
1528 		ms->offset = offset;
1529 
1530 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1531 			mdebug(offset, (char *)(void *)p,
1532 			    sizeof(union VALUETYPE));
1533 #ifndef COMPILE_ONLY
1534 			file_mdump(m);
1535 #endif
1536 		}
1537 	}
1538 
1539 	/* Verify we have enough data to match magic type */
1540 	switch (m->type) {
1541 	case FILE_BYTE:
1542 		if (nbytes < (offset + 1)) /* should alway be true */
1543 			return 0;
1544 		break;
1545 
1546 	case FILE_SHORT:
1547 	case FILE_BESHORT:
1548 	case FILE_LESHORT:
1549 		if (nbytes < (offset + 2))
1550 			return 0;
1551 		break;
1552 
1553 	case FILE_LONG:
1554 	case FILE_BELONG:
1555 	case FILE_LELONG:
1556 	case FILE_MELONG:
1557 	case FILE_DATE:
1558 	case FILE_BEDATE:
1559 	case FILE_LEDATE:
1560 	case FILE_MEDATE:
1561 	case FILE_LDATE:
1562 	case FILE_BELDATE:
1563 	case FILE_LELDATE:
1564 	case FILE_MELDATE:
1565 	case FILE_FLOAT:
1566 	case FILE_BEFLOAT:
1567 	case FILE_LEFLOAT:
1568 		if (nbytes < (offset + 4))
1569 			return 0;
1570 		break;
1571 
1572 	case FILE_DOUBLE:
1573 	case FILE_BEDOUBLE:
1574 	case FILE_LEDOUBLE:
1575 		if (nbytes < (offset + 8))
1576 			return 0;
1577 		break;
1578 
1579 	case FILE_STRING:
1580 	case FILE_PSTRING:
1581 	case FILE_SEARCH:
1582 		if (nbytes < (offset + m->vallen))
1583 			return 0;
1584 		break;
1585 
1586 	case FILE_REGEX:
1587 		if (nbytes < offset)
1588 			return 0;
1589 		break;
1590 
1591 	case FILE_INDIRECT:
1592 		if (nbytes < offset)
1593 			return 0;
1594 		sbuf = ms->o.buf;
1595 		ms->o.buf = NULL;
1596 		rv = file_softmagic(ms, s + offset, nbytes - offset,
1597 		    BINTEST, text);
1598 		if ((ms->flags & MAGIC_DEBUG) != 0)
1599 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1600 		if (rv == 1) {
1601 			rbuf = ms->o.buf;
1602 			ms->o.buf = sbuf;
1603 			if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1604 			    file_printf(ms, m->desc, offset) == -1)
1605 				return -1;
1606 			if (file_printf(ms, "%s", rbuf) == -1)
1607 				return -1;
1608 			free(rbuf);
1609 		} else
1610 			ms->o.buf = sbuf;
1611 		return rv;
1612 
1613 	case FILE_DEFAULT:	/* nothing to check */
1614 	default:
1615 		break;
1616 	}
1617 	if (!mconvert(ms, m))
1618 		return 0;
1619 	return 1;
1620 }
1621 
1622 private uint64_t
1623 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1624 {
1625 	/*
1626 	 * Convert the source args to unsigned here so that (1) the
1627 	 * compare will be unsigned as it is in strncmp() and (2) so
1628 	 * the ctype functions will work correctly without extra
1629 	 * casting.
1630 	 */
1631 	const unsigned char *a = (const unsigned char *)s1;
1632 	const unsigned char *b = (const unsigned char *)s2;
1633 	uint64_t v;
1634 
1635 	/*
1636 	 * What we want here is v = strncmp(s1, s2, len),
1637 	 * but ignoring any nulls.
1638 	 */
1639 	v = 0;
1640 	if (0L == flags) { /* normal string: do it fast */
1641 		while (len-- > 0)
1642 			if ((v = *b++ - *a++) != '\0')
1643 				break;
1644 	}
1645 	else { /* combine the others */
1646 		while (len-- > 0) {
1647 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1648 			    islower(*a)) {
1649 				if ((v = tolower(*b++) - *a++) != '\0')
1650 					break;
1651 			}
1652 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1653 			    isupper(*a)) {
1654 				if ((v = toupper(*b++) - *a++) != '\0')
1655 					break;
1656 			}
1657 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1658 			    isspace(*a)) {
1659 				a++;
1660 				if (isspace(*b++)) {
1661 					if (!isspace(*a))
1662 						while (isspace(*b))
1663 							b++;
1664 				}
1665 				else {
1666 					v = 1;
1667 					break;
1668 				}
1669 			}
1670 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1671 			    isspace(*a)) {
1672 				a++;
1673 				while (isspace(*b))
1674 					b++;
1675 			}
1676 			else {
1677 				if ((v = *b++ - *a++) != '\0')
1678 					break;
1679 			}
1680 		}
1681 	}
1682 	return v;
1683 }
1684 
1685 private uint64_t
1686 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1687 {
1688 	/*
1689 	 * XXX - The 16-bit string compare probably needs to be done
1690 	 * differently, especially if the flags are to be supported.
1691 	 * At the moment, I am unsure.
1692 	 */
1693 	flags = 0;
1694 	return file_strncmp(a, b, len, flags);
1695 }
1696 
1697 private int
1698 magiccheck(struct magic_set *ms, struct magic *m)
1699 {
1700 	uint64_t l = m->value.q;
1701 	uint64_t v;
1702 	float fl, fv;
1703 	double dl, dv;
1704 	int matched;
1705 	union VALUETYPE *p = &ms->ms_value;
1706 
1707 	switch (m->type) {
1708 	case FILE_BYTE:
1709 		v = p->b;
1710 		break;
1711 
1712 	case FILE_SHORT:
1713 	case FILE_BESHORT:
1714 	case FILE_LESHORT:
1715 		v = p->h;
1716 		break;
1717 
1718 	case FILE_LONG:
1719 	case FILE_BELONG:
1720 	case FILE_LELONG:
1721 	case FILE_MELONG:
1722 	case FILE_DATE:
1723 	case FILE_BEDATE:
1724 	case FILE_LEDATE:
1725 	case FILE_MEDATE:
1726 	case FILE_LDATE:
1727 	case FILE_BELDATE:
1728 	case FILE_LELDATE:
1729 	case FILE_MELDATE:
1730 		v = p->l;
1731 		break;
1732 
1733 	case FILE_QUAD:
1734 	case FILE_LEQUAD:
1735 	case FILE_BEQUAD:
1736 	case FILE_QDATE:
1737 	case FILE_BEQDATE:
1738 	case FILE_LEQDATE:
1739 	case FILE_QLDATE:
1740 	case FILE_BEQLDATE:
1741 	case FILE_LEQLDATE:
1742 		v = p->q;
1743 		break;
1744 
1745 	case FILE_FLOAT:
1746 	case FILE_BEFLOAT:
1747 	case FILE_LEFLOAT:
1748 		fl = m->value.f;
1749 		fv = p->f;
1750 		switch (m->reln) {
1751 		case 'x':
1752 			matched = 1;
1753 			break;
1754 
1755 		case '!':
1756 			matched = fv != fl;
1757 			break;
1758 
1759 		case '=':
1760 			matched = fv == fl;
1761 			break;
1762 
1763 		case '>':
1764 			matched = fv > fl;
1765 			break;
1766 
1767 		case '<':
1768 			matched = fv < fl;
1769 			break;
1770 
1771 		default:
1772 			matched = 0;
1773 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1774 			    m->reln);
1775 			return -1;
1776 		}
1777 		return matched;
1778 
1779 	case FILE_DOUBLE:
1780 	case FILE_BEDOUBLE:
1781 	case FILE_LEDOUBLE:
1782 		dl = m->value.d;
1783 		dv = p->d;
1784 		switch (m->reln) {
1785 		case 'x':
1786 			matched = 1;
1787 			break;
1788 
1789 		case '!':
1790 			matched = dv != dl;
1791 			break;
1792 
1793 		case '=':
1794 			matched = dv == dl;
1795 			break;
1796 
1797 		case '>':
1798 			matched = dv > dl;
1799 			break;
1800 
1801 		case '<':
1802 			matched = dv < dl;
1803 			break;
1804 
1805 		default:
1806 			matched = 0;
1807 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1808 			return -1;
1809 		}
1810 		return matched;
1811 
1812 	case FILE_DEFAULT:
1813 		l = 0;
1814 		v = 0;
1815 		break;
1816 
1817 	case FILE_STRING:
1818 	case FILE_PSTRING:
1819 		l = 0;
1820 		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1821 		break;
1822 
1823 	case FILE_BESTRING16:
1824 	case FILE_LESTRING16:
1825 		l = 0;
1826 		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1827 		break;
1828 
1829 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1830 		size_t slen;
1831 		size_t idx;
1832 
1833 		if (ms->search.s == NULL)
1834 			return 0;
1835 
1836 		slen = MIN(m->vallen, sizeof(m->value.s));
1837 		l = 0;
1838 		v = 0;
1839 
1840 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1841 			if (slen + idx > ms->search.s_len)
1842 				break;
1843 
1844 			v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
1845 			if (v == 0) {	/* found match */
1846 				ms->search.offset += idx;
1847 				break;
1848 			}
1849 		}
1850 		break;
1851 	}
1852 	case FILE_REGEX: {
1853 		int rc;
1854 		regex_t rx;
1855 		char errmsg[512];
1856 
1857 		if (ms->search.s == NULL)
1858 			return 0;
1859 
1860 		l = 0;
1861 		rc = regcomp(&rx, m->value.s,
1862 		    REG_EXTENDED|REG_NEWLINE|
1863 		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1864 		if (rc) {
1865 			(void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1866 			file_magerror(ms, "regex error %d, (%s)",
1867 			    rc, errmsg);
1868 			v = (uint64_t)-1;
1869 		}
1870 		else {
1871 			regmatch_t pmatch[1];
1872 #ifndef REG_STARTEND
1873 #define	REG_STARTEND	0
1874 			size_t l = ms->search.s_len - 1;
1875 			char c = ms->search.s[l];
1876 			((char *)(intptr_t)ms->search.s)[l] = '\0';
1877 #else
1878 			pmatch[0].rm_so = 0;
1879 			pmatch[0].rm_eo = ms->search.s_len;
1880 #endif
1881 			rc = regexec(&rx, (const char *)ms->search.s,
1882 			    1, pmatch, REG_STARTEND);
1883 #if REG_STARTEND == 0
1884 			((char *)(intptr_t)ms->search.s)[l] = c;
1885 #endif
1886 			switch (rc) {
1887 			case 0:
1888 				ms->search.s += (int)pmatch[0].rm_so;
1889 				ms->search.offset += (size_t)pmatch[0].rm_so;
1890 				ms->search.rm_len =
1891 				    (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
1892 				v = 0;
1893 				break;
1894 
1895 			case REG_NOMATCH:
1896 				v = 1;
1897 				break;
1898 
1899 			default:
1900 				(void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1901 				file_magerror(ms, "regexec error %d, (%s)",
1902 				    rc, errmsg);
1903 				v = (uint64_t)-1;
1904 				break;
1905 			}
1906 			regfree(&rx);
1907 		}
1908 		if (v == (uint64_t)-1)
1909 			return -1;
1910 		break;
1911 	}
1912 	case FILE_INDIRECT:
1913 		return 1;
1914 	default:
1915 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1916 		return -1;
1917 	}
1918 
1919 	v = file_signextend(ms, m, v);
1920 
1921 	switch (m->reln) {
1922 	case 'x':
1923 		if ((ms->flags & MAGIC_DEBUG) != 0)
1924 			(void) fprintf(stderr, "%" INT64_T_FORMAT
1925 			    "u == *any* = 1\n", (unsigned long long)v);
1926 		matched = 1;
1927 		break;
1928 
1929 	case '!':
1930 		matched = v != l;
1931 		if ((ms->flags & MAGIC_DEBUG) != 0)
1932 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
1933 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1934 			    (unsigned long long)l, matched);
1935 		break;
1936 
1937 	case '=':
1938 		matched = v == l;
1939 		if ((ms->flags & MAGIC_DEBUG) != 0)
1940 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
1941 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1942 			    (unsigned long long)l, matched);
1943 		break;
1944 
1945 	case '>':
1946 		if (m->flag & UNSIGNED) {
1947 			matched = v > l;
1948 			if ((ms->flags & MAGIC_DEBUG) != 0)
1949 				(void) fprintf(stderr, "%" INT64_T_FORMAT
1950 				    "u > %" INT64_T_FORMAT "u = %d\n",
1951 				    (unsigned long long)v,
1952 				    (unsigned long long)l, matched);
1953 		}
1954 		else {
1955 			matched = (int64_t) v > (int64_t) l;
1956 			if ((ms->flags & MAGIC_DEBUG) != 0)
1957 				(void) fprintf(stderr, "%" INT64_T_FORMAT
1958 				    "d > %" INT64_T_FORMAT "d = %d\n",
1959 				    (long long)v, (long long)l, matched);
1960 		}
1961 		break;
1962 
1963 	case '<':
1964 		if (m->flag & UNSIGNED) {
1965 			matched = v < l;
1966 			if ((ms->flags & MAGIC_DEBUG) != 0)
1967 				(void) fprintf(stderr, "%" INT64_T_FORMAT
1968 				    "u < %" INT64_T_FORMAT "u = %d\n",
1969 				    (unsigned long long)v,
1970 				    (unsigned long long)l, matched);
1971 		}
1972 		else {
1973 			matched = (int64_t) v < (int64_t) l;
1974 			if ((ms->flags & MAGIC_DEBUG) != 0)
1975 				(void) fprintf(stderr, "%" INT64_T_FORMAT
1976 				    "d < %" INT64_T_FORMAT "d = %d\n",
1977 				     (long long)v, (long long)l, matched);
1978 		}
1979 		break;
1980 
1981 	case '&':
1982 		matched = (v & l) == l;
1983 		if ((ms->flags & MAGIC_DEBUG) != 0)
1984 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
1985 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
1986 			    "x) = %d\n", (unsigned long long)v,
1987 			    (unsigned long long)l, (unsigned long long)l,
1988 			    matched);
1989 		break;
1990 
1991 	case '^':
1992 		matched = (v & l) != l;
1993 		if ((ms->flags & MAGIC_DEBUG) != 0)
1994 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
1995 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
1996 			    "x) = %d\n", (unsigned long long)v,
1997 			    (unsigned long long)l, (unsigned long long)l,
1998 			    matched);
1999 		break;
2000 
2001 	default:
2002 		matched = 0;
2003 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2004 		    m->reln);
2005 		return -1;
2006 	}
2007 
2008 	return matched;
2009 }
2010 
2011 private int
2012 handle_annotation(struct magic_set *ms, struct magic *m)
2013 {
2014 	if (ms->flags & MAGIC_APPLE) {
2015 		if (file_printf(ms, "%.8s", m->apple) == -1)
2016 			return -1;
2017 		return 1;
2018 	}
2019 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2020 		if (file_printf(ms, "%s", m->mimetype) == -1)
2021 			return -1;
2022 		return 1;
2023 	}
2024 	return 0;
2025 }
2026 
2027 private int
2028 print_sep(struct magic_set *ms, int firstline)
2029 {
2030 	if (ms->flags & MAGIC_MIME)
2031 		return 0;
2032 	if (firstline)
2033 		return 0;
2034 	/*
2035 	 * we found another match
2036 	 * put a newline and '-' to do some simple formatting
2037 	 */
2038 	return file_printf(ms, "\n- ");
2039 }
2040