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