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