xref: /dragonfly/contrib/file/src/softmagic.c (revision 956939d5)
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.135 2009/03/27 22:42:49 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 & BINTEST) != 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 		/*
172 		 * If we are going to print something, we'll need to print
173 		 * a blank before we print something else.
174 		 */
175 		if (*m->desc) {
176 			need_separator = 1;
177 			printed_something = 1;
178 			if ((e = handle_annotation(ms, m)) != 0)
179 				return e;
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 				/*
255 				 * If we are going to print something,
256 				 * make sure that we have a separator first.
257 				 */
258 				if (*m->desc) {
259 					if ((e = handle_annotation(ms, m)) != 0)
260 						return e;
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++;
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 ms->offset + sizeof(char);
586 
587   	case FILE_SHORT:
588   	case FILE_BESHORT:
589   	case FILE_LESHORT:
590 		return ms->offset + sizeof(short);
591 
592   	case FILE_LONG:
593   	case FILE_BELONG:
594   	case FILE_LELONG:
595   	case FILE_MELONG:
596 		return ms->offset + sizeof(int32_t);
597 
598   	case FILE_QUAD:
599   	case FILE_BEQUAD:
600   	case FILE_LEQUAD:
601 		return 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 = ms->offset + strlen(p->s);
616 			if (m->type == FILE_PSTRING)
617 				t++;
618 			return t;
619 		}
620 
621 	case FILE_DATE:
622 	case FILE_BEDATE:
623 	case FILE_LEDATE:
624 	case FILE_MEDATE:
625 		return ms->offset + sizeof(time_t);
626 
627 	case FILE_LDATE:
628 	case FILE_BELDATE:
629 	case FILE_LELDATE:
630 	case FILE_MELDATE:
631 		return ms->offset + sizeof(time_t);
632 
633 	case FILE_QDATE:
634 	case FILE_BEQDATE:
635 	case FILE_LEQDATE:
636 		return ms->offset + sizeof(uint64_t);
637 
638 	case FILE_QLDATE:
639 	case FILE_BEQLDATE:
640 	case FILE_LEQLDATE:
641 		return ms->offset + sizeof(uint64_t);
642 
643   	case FILE_FLOAT:
644   	case FILE_BEFLOAT:
645   	case FILE_LEFLOAT:
646 		return ms->offset + sizeof(float);
647 
648   	case FILE_DOUBLE:
649   	case FILE_BEDOUBLE:
650   	case FILE_LEDOUBLE:
651 		return ms->offset + sizeof(double);
652   		break;
653 
654 	case FILE_REGEX:
655 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
656 			return ms->search.offset;
657 		else
658 			return ms->search.offset + ms->search.rm_len;
659 
660 	case FILE_SEARCH:
661 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
662 			return ms->search.offset;
663 		else
664 			return 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 #if 0
794 		/* Why? breaks magic numbers that end with \xa */
795 		len = strlen(p->s);
796 		if (len-- && p->s[len] == '\n')
797 			p->s[len] = '\0';
798 #endif
799 		return 1;
800 	}
801 	case FILE_PSTRING: {
802 		char *ptr1 = p->s, *ptr2 = ptr1 + 1;
803 		size_t len = *p->s;
804 		if (len >= sizeof(p->s))
805 			len = sizeof(p->s) - 1;
806 		while (len--)
807 			*ptr1++ = *ptr2++;
808 		*ptr1 = '\0';
809 #if 0
810 		/* Why? breaks magic numbers that end with \xa */
811 		len = strlen(p->s);
812 		if (len-- && p->s[len] == '\n')
813 			p->s[len] = '\0';
814 #endif
815 		return 1;
816 	}
817 	case FILE_BESHORT:
818 		p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
819 		cvt_16(p, m);
820 		return 1;
821 	case FILE_BELONG:
822 	case FILE_BEDATE:
823 	case FILE_BELDATE:
824 		p->l = (int32_t)
825 		    ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
826 		cvt_32(p, m);
827 		return 1;
828 	case FILE_BEQUAD:
829 	case FILE_BEQDATE:
830 	case FILE_BEQLDATE:
831 		p->q = (uint64_t)
832 		    (((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
833 		     ((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
834 		     ((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
835 		     ((uint64_t)p->hq[6]<<8)|((uint64_t)p->hq[7]));
836 		cvt_64(p, m);
837 		return 1;
838 	case FILE_LESHORT:
839 		p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
840 		cvt_16(p, m);
841 		return 1;
842 	case FILE_LELONG:
843 	case FILE_LEDATE:
844 	case FILE_LELDATE:
845 		p->l = (int32_t)
846 		    ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
847 		cvt_32(p, m);
848 		return 1;
849 	case FILE_LEQUAD:
850 	case FILE_LEQDATE:
851 	case FILE_LEQLDATE:
852 		p->q = (uint64_t)
853 		    (((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
854 		     ((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
855 		     ((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
856 		     ((uint64_t)p->hq[1]<<8)|((uint64_t)p->hq[0]));
857 		cvt_64(p, m);
858 		return 1;
859 	case FILE_MELONG:
860 	case FILE_MEDATE:
861 	case FILE_MELDATE:
862 		p->l = (int32_t)
863 		    ((p->hl[1]<<24)|(p->hl[0]<<16)|(p->hl[3]<<8)|(p->hl[2]));
864 		cvt_32(p, m);
865 		return 1;
866 	case FILE_FLOAT:
867 		cvt_float(p, m);
868 		return 1;
869 	case FILE_BEFLOAT:
870 		p->l =  ((uint32_t)p->hl[0]<<24)|((uint32_t)p->hl[1]<<16)|
871 			((uint32_t)p->hl[2]<<8) |((uint32_t)p->hl[3]);
872 		cvt_float(p, m);
873 		return 1;
874 	case FILE_LEFLOAT:
875 		p->l =  ((uint32_t)p->hl[3]<<24)|((uint32_t)p->hl[2]<<16)|
876 			((uint32_t)p->hl[1]<<8) |((uint32_t)p->hl[0]);
877 		cvt_float(p, m);
878 		return 1;
879 	case FILE_DOUBLE:
880 		cvt_double(p, m);
881 		return 1;
882 	case FILE_BEDOUBLE:
883 		p->q =  ((uint64_t)p->hq[0]<<56)|((uint64_t)p->hq[1]<<48)|
884 			((uint64_t)p->hq[2]<<40)|((uint64_t)p->hq[3]<<32)|
885 			((uint64_t)p->hq[4]<<24)|((uint64_t)p->hq[5]<<16)|
886 			((uint64_t)p->hq[6]<<8) |((uint64_t)p->hq[7]);
887 		cvt_double(p, m);
888 		return 1;
889 	case FILE_LEDOUBLE:
890 		p->q =  ((uint64_t)p->hq[7]<<56)|((uint64_t)p->hq[6]<<48)|
891 			((uint64_t)p->hq[5]<<40)|((uint64_t)p->hq[4]<<32)|
892 			((uint64_t)p->hq[3]<<24)|((uint64_t)p->hq[2]<<16)|
893 			((uint64_t)p->hq[1]<<8) |((uint64_t)p->hq[0]);
894 		cvt_double(p, m);
895 		return 1;
896 	case FILE_REGEX:
897 	case FILE_SEARCH:
898 	case FILE_DEFAULT:
899 		return 1;
900 	default:
901 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
902 		return 0;
903 	}
904 }
905 
906 
907 private void
908 mdebug(uint32_t offset, const char *str, size_t len)
909 {
910 	(void) fprintf(stderr, "mget @%d: ", offset);
911 	file_showstr(stderr, str, len);
912 	(void) fputc('\n', stderr);
913 	(void) fputc('\n', stderr);
914 }
915 
916 private int
917 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
918     const unsigned char *s, uint32_t offset, size_t nbytes, size_t linecnt)
919 {
920 	/*
921 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
922 	 * anything, but setup pointers into the source
923 	 */
924 	if (indir == 0) {
925 		switch (type) {
926 		case FILE_SEARCH:
927 			ms->search.s = (const char *)s + offset;
928 			ms->search.s_len = nbytes - offset;
929 			ms->search.offset = offset;
930 			return 0;
931 
932 		case FILE_REGEX: {
933 			const char *b;
934 			const char *c;
935 			const char *last;	/* end of search region */
936 			const char *buf;	/* start of search region */
937 			const char *end;
938 			size_t lines;
939 
940 			if (s == NULL) {
941 				ms->search.s_len = 0;
942 				ms->search.s = NULL;
943 				return 0;
944 			}
945 			buf = (const char *)s + offset;
946 			end = last = (const char *)s + nbytes;
947 			/* mget() guarantees buf <= last */
948 			for (lines = linecnt, b = buf;
949 			     lines && ((b = memchr(c = b, '\n', end - b)) || (b = memchr(c, '\r', end - c)));
950 			     lines--, b++) {
951 				last = b;
952 				if (b[0] == '\r' && b[1] == '\n')
953 					b++;
954 			}
955 			if (lines)
956 				last = (const char *)s + nbytes;
957 
958 			ms->search.s = buf;
959 			ms->search.s_len = last - buf;
960 			ms->search.offset = offset;
961 			ms->search.rm_len = 0;
962 			return 0;
963 		}
964 		case FILE_BESTRING16:
965 		case FILE_LESTRING16: {
966 			const unsigned char *src = s + offset;
967 			const unsigned char *esrc = s + nbytes;
968 			char *dst = p->s;
969 			char *edst = &p->s[sizeof(p->s) - 1];
970 
971 			if (type == FILE_BESTRING16)
972 				src++;
973 
974 			/* check for pointer overflow */
975 			if (src < s) {
976 				file_magerror(ms, "invalid offset %u in mcopy()",
977 				    offset);
978 				return -1;
979 			}
980 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
981 				if (dst < edst)
982 					*dst = *src;
983 				else
984 					break;
985 				if (*dst == '\0') {
986 					if (type == FILE_BESTRING16 ?
987 					    *(src - 1) != '\0' :
988 					    *(src + 1) != '\0')
989 						*dst = ' ';
990 				}
991 			}
992 			*edst = '\0';
993 			return 0;
994 		}
995 		case FILE_STRING:	/* XXX - these two should not need */
996 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
997 		default:
998 			break;
999 		}
1000 	}
1001 
1002 	if (offset >= nbytes) {
1003 		(void)memset(p, '\0', sizeof(*p));
1004 		return 0;
1005 	}
1006 	if (nbytes - offset < sizeof(*p))
1007 		nbytes = nbytes - offset;
1008 	else
1009 		nbytes = sizeof(*p);
1010 
1011 	(void)memcpy(p, s + offset, nbytes);
1012 
1013 	/*
1014 	 * the usefulness of padding with zeroes eludes me, it
1015 	 * might even cause problems
1016 	 */
1017 	if (nbytes < sizeof(*p))
1018 		(void)memset(((char *)(void *)p) + nbytes, '\0',
1019 		    sizeof(*p) - nbytes);
1020 	return 0;
1021 }
1022 
1023 private int
1024 mget(struct magic_set *ms, const unsigned char *s,
1025     struct magic *m, size_t nbytes, unsigned int cont_level)
1026 {
1027 	uint32_t offset = ms->offset;
1028 	uint32_t count = m->str_range;
1029 	union VALUETYPE *p = &ms->ms_value;
1030 
1031 	if (mcopy(ms, p, m->type, m->flag & INDIR, s, offset, nbytes, count) == -1)
1032 		return -1;
1033 
1034 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1035 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1036 #ifndef COMPILE_ONLY
1037 		file_mdump(m);
1038 #endif
1039 	}
1040 
1041 	if (m->flag & INDIR) {
1042 		int off = m->in_offset;
1043 		if (m->in_op & FILE_OPINDIRECT) {
1044 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1045 			    ((const void *)(s + offset + off)));
1046 			switch (m->in_type) {
1047 			case FILE_BYTE:
1048 				off = q->b;
1049 				break;
1050 			case FILE_SHORT:
1051 				off = q->h;
1052 				break;
1053 			case FILE_BESHORT:
1054 				off = (short)((q->hs[0]<<8)|(q->hs[1]));
1055 				break;
1056 			case FILE_LESHORT:
1057 				off = (short)((q->hs[1]<<8)|(q->hs[0]));
1058 				break;
1059 			case FILE_LONG:
1060 				off = q->l;
1061 				break;
1062 			case FILE_BELONG:
1063 			case FILE_BEID3:
1064 				off = (int32_t)((q->hl[0]<<24)|(q->hl[1]<<16)|
1065 						 (q->hl[2]<<8)|(q->hl[3]));
1066 				break;
1067 			case FILE_LEID3:
1068 			case FILE_LELONG:
1069 				off = (int32_t)((q->hl[3]<<24)|(q->hl[2]<<16)|
1070 						 (q->hl[1]<<8)|(q->hl[0]));
1071 				break;
1072 			case FILE_MELONG:
1073 				off = (int32_t)((q->hl[1]<<24)|(q->hl[0]<<16)|
1074 						 (q->hl[3]<<8)|(q->hl[2]));
1075 				break;
1076 			}
1077 		}
1078 		switch (m->in_type) {
1079 		case FILE_BYTE:
1080 			if (nbytes < (offset + 1))
1081 				return 0;
1082 			if (off) {
1083 				switch (m->in_op & FILE_OPS_MASK) {
1084 				case FILE_OPAND:
1085 					offset = p->b & off;
1086 					break;
1087 				case FILE_OPOR:
1088 					offset = p->b | off;
1089 					break;
1090 				case FILE_OPXOR:
1091 					offset = p->b ^ off;
1092 					break;
1093 				case FILE_OPADD:
1094 					offset = p->b + off;
1095 					break;
1096 				case FILE_OPMINUS:
1097 					offset = p->b - off;
1098 					break;
1099 				case FILE_OPMULTIPLY:
1100 					offset = p->b * off;
1101 					break;
1102 				case FILE_OPDIVIDE:
1103 					offset = p->b / off;
1104 					break;
1105 				case FILE_OPMODULO:
1106 					offset = p->b % off;
1107 					break;
1108 				}
1109 			} else
1110 				offset = p->b;
1111 			if (m->in_op & FILE_OPINVERSE)
1112 				offset = ~offset;
1113 			break;
1114 		case FILE_BESHORT:
1115 			if (nbytes < (offset + 2))
1116 				return 0;
1117 			if (off) {
1118 				switch (m->in_op & FILE_OPS_MASK) {
1119 				case FILE_OPAND:
1120 					offset = (short)((p->hs[0]<<8)|
1121 							 (p->hs[1])) &
1122 						 off;
1123 					break;
1124 				case FILE_OPOR:
1125 					offset = (short)((p->hs[0]<<8)|
1126 							 (p->hs[1])) |
1127 						 off;
1128 					break;
1129 				case FILE_OPXOR:
1130 					offset = (short)((p->hs[0]<<8)|
1131 							 (p->hs[1])) ^
1132 						 off;
1133 					break;
1134 				case FILE_OPADD:
1135 					offset = (short)((p->hs[0]<<8)|
1136 							 (p->hs[1])) +
1137 						 off;
1138 					break;
1139 				case FILE_OPMINUS:
1140 					offset = (short)((p->hs[0]<<8)|
1141 							 (p->hs[1])) -
1142 						 off;
1143 					break;
1144 				case FILE_OPMULTIPLY:
1145 					offset = (short)((p->hs[0]<<8)|
1146 							 (p->hs[1])) *
1147 						 off;
1148 					break;
1149 				case FILE_OPDIVIDE:
1150 					offset = (short)((p->hs[0]<<8)|
1151 							 (p->hs[1])) /
1152 						 off;
1153 					break;
1154 				case FILE_OPMODULO:
1155 					offset = (short)((p->hs[0]<<8)|
1156 							 (p->hs[1])) %
1157 						 off;
1158 					break;
1159 				}
1160 			} else
1161 				offset = (short)((p->hs[0]<<8)|
1162 						 (p->hs[1]));
1163 			if (m->in_op & FILE_OPINVERSE)
1164 				offset = ~offset;
1165 			break;
1166 		case FILE_LESHORT:
1167 			if (nbytes < (offset + 2))
1168 				return 0;
1169 			if (off) {
1170 				switch (m->in_op & FILE_OPS_MASK) {
1171 				case FILE_OPAND:
1172 					offset = (short)((p->hs[1]<<8)|
1173 							 (p->hs[0])) &
1174 						 off;
1175 					break;
1176 				case FILE_OPOR:
1177 					offset = (short)((p->hs[1]<<8)|
1178 							 (p->hs[0])) |
1179 						 off;
1180 					break;
1181 				case FILE_OPXOR:
1182 					offset = (short)((p->hs[1]<<8)|
1183 							 (p->hs[0])) ^
1184 						 off;
1185 					break;
1186 				case FILE_OPADD:
1187 					offset = (short)((p->hs[1]<<8)|
1188 							 (p->hs[0])) +
1189 						 off;
1190 					break;
1191 				case FILE_OPMINUS:
1192 					offset = (short)((p->hs[1]<<8)|
1193 							 (p->hs[0])) -
1194 						 off;
1195 					break;
1196 				case FILE_OPMULTIPLY:
1197 					offset = (short)((p->hs[1]<<8)|
1198 							 (p->hs[0])) *
1199 						 off;
1200 					break;
1201 				case FILE_OPDIVIDE:
1202 					offset = (short)((p->hs[1]<<8)|
1203 							 (p->hs[0])) /
1204 						 off;
1205 					break;
1206 				case FILE_OPMODULO:
1207 					offset = (short)((p->hs[1]<<8)|
1208 							 (p->hs[0])) %
1209 						 off;
1210 					break;
1211 				}
1212 			} else
1213 				offset = (short)((p->hs[1]<<8)|
1214 						 (p->hs[0]));
1215 			if (m->in_op & FILE_OPINVERSE)
1216 				offset = ~offset;
1217 			break;
1218 		case FILE_SHORT:
1219 			if (nbytes < (offset + 2))
1220 				return 0;
1221 			if (off) {
1222 				switch (m->in_op & FILE_OPS_MASK) {
1223 				case FILE_OPAND:
1224 					offset = p->h & off;
1225 					break;
1226 				case FILE_OPOR:
1227 					offset = p->h | off;
1228 					break;
1229 				case FILE_OPXOR:
1230 					offset = p->h ^ off;
1231 					break;
1232 				case FILE_OPADD:
1233 					offset = p->h + off;
1234 					break;
1235 				case FILE_OPMINUS:
1236 					offset = p->h - off;
1237 					break;
1238 				case FILE_OPMULTIPLY:
1239 					offset = p->h * off;
1240 					break;
1241 				case FILE_OPDIVIDE:
1242 					offset = p->h / off;
1243 					break;
1244 				case FILE_OPMODULO:
1245 					offset = p->h % off;
1246 					break;
1247 				}
1248 			}
1249 			else
1250 				offset = p->h;
1251 			if (m->in_op & FILE_OPINVERSE)
1252 				offset = ~offset;
1253 			break;
1254 		case FILE_BELONG:
1255 		case FILE_BEID3:
1256 			if (nbytes < (offset + 4))
1257 				return 0;
1258 			if (off) {
1259 				switch (m->in_op & FILE_OPS_MASK) {
1260 				case FILE_OPAND:
1261 					offset = (int32_t)((p->hl[0]<<24)|
1262 							 (p->hl[1]<<16)|
1263 							 (p->hl[2]<<8)|
1264 							 (p->hl[3])) &
1265 						 off;
1266 					break;
1267 				case FILE_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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_OPMODULO:
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 				}
1317 			} else
1318 				offset = (int32_t)((p->hl[0]<<24)|
1319 						 (p->hl[1]<<16)|
1320 						 (p->hl[2]<<8)|
1321 						 (p->hl[3]));
1322 			if (m->in_op & FILE_OPINVERSE)
1323 				offset = ~offset;
1324 			break;
1325 		case FILE_LELONG:
1326 		case FILE_LEID3:
1327 			if (nbytes < (offset + 4))
1328 				return 0;
1329 			if (off) {
1330 				switch (m->in_op & FILE_OPS_MASK) {
1331 				case FILE_OPAND:
1332 					offset = (int32_t)((p->hl[3]<<24)|
1333 							 (p->hl[2]<<16)|
1334 							 (p->hl[1]<<8)|
1335 							 (p->hl[0])) &
1336 						 off;
1337 					break;
1338 				case FILE_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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_OPMODULO:
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 				}
1388 			} else
1389 				offset = (int32_t)((p->hl[3]<<24)|
1390 						 (p->hl[2]<<16)|
1391 						 (p->hl[1]<<8)|
1392 						 (p->hl[0]));
1393 			if (m->in_op & FILE_OPINVERSE)
1394 				offset = ~offset;
1395 			break;
1396 		case FILE_MELONG:
1397 			if (nbytes < (offset + 4))
1398 				return 0;
1399 			if (off) {
1400 				switch (m->in_op & FILE_OPS_MASK) {
1401 				case FILE_OPAND:
1402 					offset = (int32_t)((p->hl[1]<<24)|
1403 							 (p->hl[0]<<16)|
1404 							 (p->hl[3]<<8)|
1405 							 (p->hl[2])) &
1406 						 off;
1407 					break;
1408 				case FILE_OPOR:
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_OPXOR:
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_OPADD:
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_OPMINUS:
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_OPMULTIPLY:
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_OPDIVIDE:
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_OPMODULO:
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 				}
1458 			} else
1459 				offset = (int32_t)((p->hl[1]<<24)|
1460 						 (p->hl[0]<<16)|
1461 						 (p->hl[3]<<8)|
1462 						 (p->hl[2]));
1463 			if (m->in_op & FILE_OPINVERSE)
1464 				offset = ~offset;
1465 			break;
1466 		case FILE_LONG:
1467 			if (nbytes < (offset + 4))
1468 				return 0;
1469 			if (off) {
1470 				switch (m->in_op & FILE_OPS_MASK) {
1471 				case FILE_OPAND:
1472 					offset = p->l & off;
1473 					break;
1474 				case FILE_OPOR:
1475 					offset = p->l | off;
1476 					break;
1477 				case FILE_OPXOR:
1478 					offset = p->l ^ off;
1479 					break;
1480 				case FILE_OPADD:
1481 					offset = p->l + off;
1482 					break;
1483 				case FILE_OPMINUS:
1484 					offset = p->l - off;
1485 					break;
1486 				case FILE_OPMULTIPLY:
1487 					offset = p->l * off;
1488 					break;
1489 				case FILE_OPDIVIDE:
1490 					offset = p->l / off;
1491 					break;
1492 				case FILE_OPMODULO:
1493 					offset = p->l % off;
1494 					break;
1495 				}
1496 			} else
1497 				offset = p->l;
1498 			if (m->in_op & FILE_OPINVERSE)
1499 				offset = ~offset;
1500 			break;
1501 		}
1502 
1503 		switch (m->in_type) {
1504 		case FILE_LEID3:
1505 		case FILE_BEID3:
1506 			offset = ((((offset >>  0) & 0x7f) <<  0) |
1507 				 (((offset >>  8) & 0x7f) <<  7) |
1508 				 (((offset >> 16) & 0x7f) << 14) |
1509 				 (((offset >> 24) & 0x7f) << 21)) + 10;
1510 			break;
1511 		default:
1512 			break;
1513 		}
1514 
1515 		if (m->flag & INDIROFFADD) {
1516 			offset += ms->c.li[cont_level-1].off;
1517 		}
1518 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, count) == -1)
1519 			return -1;
1520 		ms->offset = offset;
1521 
1522 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1523 			mdebug(offset, (char *)(void *)p,
1524 			    sizeof(union VALUETYPE));
1525 #ifndef COMPILE_ONLY
1526 			file_mdump(m);
1527 #endif
1528 		}
1529 	}
1530 
1531 	/* Verify we have enough data to match magic type */
1532 	switch (m->type) {
1533 	case FILE_BYTE:
1534 		if (nbytes < (offset + 1)) /* should alway be true */
1535 			return 0;
1536 		break;
1537 
1538 	case FILE_SHORT:
1539 	case FILE_BESHORT:
1540 	case FILE_LESHORT:
1541 		if (nbytes < (offset + 2))
1542 			return 0;
1543 		break;
1544 
1545 	case FILE_LONG:
1546 	case FILE_BELONG:
1547 	case FILE_LELONG:
1548 	case FILE_MELONG:
1549 	case FILE_DATE:
1550 	case FILE_BEDATE:
1551 	case FILE_LEDATE:
1552 	case FILE_MEDATE:
1553 	case FILE_LDATE:
1554 	case FILE_BELDATE:
1555 	case FILE_LELDATE:
1556 	case FILE_MELDATE:
1557 	case FILE_FLOAT:
1558 	case FILE_BEFLOAT:
1559 	case FILE_LEFLOAT:
1560 		if (nbytes < (offset + 4))
1561 			return 0;
1562 		break;
1563 
1564 	case FILE_DOUBLE:
1565 	case FILE_BEDOUBLE:
1566 	case FILE_LEDOUBLE:
1567 		if (nbytes < (offset + 8))
1568 			return 0;
1569 		break;
1570 
1571 	case FILE_STRING:
1572 	case FILE_PSTRING:
1573 	case FILE_SEARCH:
1574 		if (nbytes < (offset + m->vallen))
1575 			return 0;
1576 		break;
1577 
1578 	case FILE_REGEX:
1579 		if (nbytes < offset)
1580 			return 0;
1581 		break;
1582 
1583 	case FILE_INDIRECT:
1584 	  	if ((ms->flags & (MAGIC_MIME|MAGIC_APPLE)) == 0 &&
1585 		    file_printf(ms, m->desc) == -1)
1586 			return -1;
1587 		if (nbytes < offset)
1588 			return 0;
1589 		return file_softmagic(ms, s + offset, nbytes - offset,
1590 		    BINTEST);
1591 
1592 	case FILE_DEFAULT:	/* nothing to check */
1593 	default:
1594 		break;
1595 	}
1596 	if (!mconvert(ms, m))
1597 		return 0;
1598 	return 1;
1599 }
1600 
1601 private uint64_t
1602 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1603 {
1604 	/*
1605 	 * Convert the source args to unsigned here so that (1) the
1606 	 * compare will be unsigned as it is in strncmp() and (2) so
1607 	 * the ctype functions will work correctly without extra
1608 	 * casting.
1609 	 */
1610 	const unsigned char *a = (const unsigned char *)s1;
1611 	const unsigned char *b = (const unsigned char *)s2;
1612 	uint64_t v;
1613 
1614 	/*
1615 	 * What we want here is v = strncmp(s1, s2, len),
1616 	 * but ignoring any nulls.
1617 	 */
1618 	v = 0;
1619 	if (0L == flags) { /* normal string: do it fast */
1620 		while (len-- > 0)
1621 			if ((v = *b++ - *a++) != '\0')
1622 				break;
1623 	}
1624 	else { /* combine the others */
1625 		while (len-- > 0) {
1626 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1627 			    islower(*a)) {
1628 				if ((v = tolower(*b++) - *a++) != '\0')
1629 					break;
1630 			}
1631 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1632 			    isupper(*a)) {
1633 				if ((v = toupper(*b++) - *a++) != '\0')
1634 					break;
1635 			}
1636 			else if ((flags & STRING_COMPACT_BLANK) &&
1637 			    isspace(*a)) {
1638 				a++;
1639 				if (isspace(*b++)) {
1640 					while (isspace(*b))
1641 						b++;
1642 				}
1643 				else {
1644 					v = 1;
1645 					break;
1646 				}
1647 			}
1648 			else if ((flags & STRING_COMPACT_OPTIONAL_BLANK) &&
1649 			    isspace(*a)) {
1650 				a++;
1651 				while (isspace(*b))
1652 					b++;
1653 			}
1654 			else {
1655 				if ((v = *b++ - *a++) != '\0')
1656 					break;
1657 			}
1658 		}
1659 	}
1660 	return v;
1661 }
1662 
1663 private uint64_t
1664 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1665 {
1666 	/*
1667 	 * XXX - The 16-bit string compare probably needs to be done
1668 	 * differently, especially if the flags are to be supported.
1669 	 * At the moment, I am unsure.
1670 	 */
1671 	flags = 0;
1672 	return file_strncmp(a, b, len, flags);
1673 }
1674 
1675 private int
1676 magiccheck(struct magic_set *ms, struct magic *m)
1677 {
1678 	uint64_t l = m->value.q;
1679 	uint64_t v;
1680 	float fl, fv;
1681 	double dl, dv;
1682 	int matched;
1683 	union VALUETYPE *p = &ms->ms_value;
1684 
1685 	switch (m->type) {
1686 	case FILE_BYTE:
1687 		v = p->b;
1688 		break;
1689 
1690 	case FILE_SHORT:
1691 	case FILE_BESHORT:
1692 	case FILE_LESHORT:
1693 		v = p->h;
1694 		break;
1695 
1696 	case FILE_LONG:
1697 	case FILE_BELONG:
1698 	case FILE_LELONG:
1699 	case FILE_MELONG:
1700 	case FILE_DATE:
1701 	case FILE_BEDATE:
1702 	case FILE_LEDATE:
1703 	case FILE_MEDATE:
1704 	case FILE_LDATE:
1705 	case FILE_BELDATE:
1706 	case FILE_LELDATE:
1707 	case FILE_MELDATE:
1708 		v = p->l;
1709 		break;
1710 
1711 	case FILE_QUAD:
1712 	case FILE_LEQUAD:
1713 	case FILE_BEQUAD:
1714 	case FILE_QDATE:
1715 	case FILE_BEQDATE:
1716 	case FILE_LEQDATE:
1717 	case FILE_QLDATE:
1718 	case FILE_BEQLDATE:
1719 	case FILE_LEQLDATE:
1720 		v = p->q;
1721 		break;
1722 
1723 	case FILE_FLOAT:
1724 	case FILE_BEFLOAT:
1725 	case FILE_LEFLOAT:
1726 		fl = m->value.f;
1727 		fv = p->f;
1728 		switch (m->reln) {
1729 		case 'x':
1730 			matched = 1;
1731 			break;
1732 
1733 		case '!':
1734 			matched = fv != fl;
1735 			break;
1736 
1737 		case '=':
1738 			matched = fv == fl;
1739 			break;
1740 
1741 		case '>':
1742 			matched = fv > fl;
1743 			break;
1744 
1745 		case '<':
1746 			matched = fv < fl;
1747 			break;
1748 
1749 		default:
1750 			matched = 0;
1751 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1752 			    m->reln);
1753 			return -1;
1754 		}
1755 		return matched;
1756 
1757 	case FILE_DOUBLE:
1758 	case FILE_BEDOUBLE:
1759 	case FILE_LEDOUBLE:
1760 		dl = m->value.d;
1761 		dv = p->d;
1762 		switch (m->reln) {
1763 		case 'x':
1764 			matched = 1;
1765 			break;
1766 
1767 		case '!':
1768 			matched = dv != dl;
1769 			break;
1770 
1771 		case '=':
1772 			matched = dv == dl;
1773 			break;
1774 
1775 		case '>':
1776 			matched = dv > dl;
1777 			break;
1778 
1779 		case '<':
1780 			matched = dv < dl;
1781 			break;
1782 
1783 		default:
1784 			matched = 0;
1785 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1786 			return -1;
1787 		}
1788 		return matched;
1789 
1790 	case FILE_DEFAULT:
1791 		l = 0;
1792 		v = 0;
1793 		break;
1794 
1795 	case FILE_STRING:
1796 	case FILE_PSTRING:
1797 		l = 0;
1798 		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1799 		break;
1800 
1801 	case FILE_BESTRING16:
1802 	case FILE_LESTRING16:
1803 		l = 0;
1804 		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1805 		break;
1806 
1807 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1808 		size_t slen;
1809 		size_t idx;
1810 
1811 		if (ms->search.s == NULL)
1812 			return 0;
1813 
1814 		slen = MIN(m->vallen, sizeof(m->value.s));
1815 		l = 0;
1816 		v = 0;
1817 
1818 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1819 			if (slen + idx > ms->search.s_len)
1820 				break;
1821 
1822 			v = file_strncmp(m->value.s, ms->search.s + idx, slen, m->str_flags);
1823 			if (v == 0) {	/* found match */
1824 				ms->search.offset += idx;
1825 				break;
1826 			}
1827 		}
1828 		break;
1829 	}
1830 	case FILE_REGEX: {
1831 		int rc;
1832 		regex_t rx;
1833 		char errmsg[512];
1834 
1835 		if (ms->search.s == NULL)
1836 			return 0;
1837 
1838 		l = 0;
1839 		rc = regcomp(&rx, m->value.s,
1840 		    REG_EXTENDED|REG_NEWLINE|
1841 		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
1842 		if (rc) {
1843 			(void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1844 			file_magerror(ms, "regex error %d, (%s)",
1845 			    rc, errmsg);
1846 			v = (uint64_t)-1;
1847 		}
1848 		else {
1849 			regmatch_t pmatch[1];
1850 #ifndef REG_STARTEND
1851 #define	REG_STARTEND	0
1852 			size_t l = ms->search.s_len - 1;
1853 			char c = ms->search.s[l];
1854 			((char *)(intptr_t)ms->search.s)[l] = '\0';
1855 #else
1856 			pmatch[0].rm_so = 0;
1857 			pmatch[0].rm_eo = ms->search.s_len;
1858 #endif
1859 			rc = regexec(&rx, (const char *)ms->search.s,
1860 			    1, pmatch, REG_STARTEND);
1861 #if REG_STARTEND == 0
1862 			((char *)(intptr_t)ms->search.s)[l] = c;
1863 #endif
1864 			switch (rc) {
1865 			case 0:
1866 				ms->search.s += (int)pmatch[0].rm_so;
1867 				ms->search.offset += (size_t)pmatch[0].rm_so;
1868 				ms->search.rm_len =
1869 				    (size_t)(pmatch[0].rm_eo - pmatch[0].rm_so);
1870 				v = 0;
1871 				break;
1872 
1873 			case REG_NOMATCH:
1874 				v = 1;
1875 				break;
1876 
1877 			default:
1878 				(void)regerror(rc, &rx, errmsg, sizeof(errmsg));
1879 				file_magerror(ms, "regexec error %d, (%s)",
1880 				    rc, errmsg);
1881 				v = (uint64_t)-1;
1882 				break;
1883 			}
1884 			regfree(&rx);
1885 		}
1886 		if (v == (uint64_t)-1)
1887 			return -1;
1888 		break;
1889 	}
1890 	case FILE_INDIRECT:
1891 		return 1;
1892 	default:
1893 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1894 		return -1;
1895 	}
1896 
1897 	v = file_signextend(ms, m, v);
1898 
1899 	switch (m->reln) {
1900 	case 'x':
1901 		if ((ms->flags & MAGIC_DEBUG) != 0)
1902 			(void) fprintf(stderr, "%llu == *any* = 1\n",
1903 			    (unsigned long long)v);
1904 		matched = 1;
1905 		break;
1906 
1907 	case '!':
1908 		matched = v != l;
1909 		if ((ms->flags & MAGIC_DEBUG) != 0)
1910 			(void) fprintf(stderr, "%llu != %llu = %d\n",
1911 			    (unsigned long long)v, (unsigned long long)l,
1912 			    matched);
1913 		break;
1914 
1915 	case '=':
1916 		matched = v == l;
1917 		if ((ms->flags & MAGIC_DEBUG) != 0)
1918 			(void) fprintf(stderr, "%llu == %llu = %d\n",
1919 			    (unsigned long long)v, (unsigned long long)l,
1920 			    matched);
1921 		break;
1922 
1923 	case '>':
1924 		if (m->flag & UNSIGNED) {
1925 			matched = v > l;
1926 			if ((ms->flags & MAGIC_DEBUG) != 0)
1927 				(void) fprintf(stderr, "%llu > %llu = %d\n",
1928 				    (unsigned long long)v,
1929 				    (unsigned long long)l, matched);
1930 		}
1931 		else {
1932 			matched = (int64_t) v > (int64_t) l;
1933 			if ((ms->flags & MAGIC_DEBUG) != 0)
1934 				(void) fprintf(stderr, "%lld > %lld = %d\n",
1935 				    (long long)v, (long long)l, matched);
1936 		}
1937 		break;
1938 
1939 	case '<':
1940 		if (m->flag & UNSIGNED) {
1941 			matched = v < l;
1942 			if ((ms->flags & MAGIC_DEBUG) != 0)
1943 				(void) fprintf(stderr, "%llu < %llu = %d\n",
1944 				    (unsigned long long)v,
1945 				    (unsigned long long)l, matched);
1946 		}
1947 		else {
1948 			matched = (int64_t) v < (int64_t) l;
1949 			if ((ms->flags & MAGIC_DEBUG) != 0)
1950 				(void) fprintf(stderr, "%lld < %lld = %d\n",
1951 				       (long long)v, (long long)l, matched);
1952 		}
1953 		break;
1954 
1955 	case '&':
1956 		matched = (v & l) == l;
1957 		if ((ms->flags & MAGIC_DEBUG) != 0)
1958 			(void) fprintf(stderr, "((%llx & %llx) == %llx) = %d\n",
1959 			    (unsigned long long)v, (unsigned long long)l,
1960 			    (unsigned long long)l, matched);
1961 		break;
1962 
1963 	case '^':
1964 		matched = (v & l) != l;
1965 		if ((ms->flags & MAGIC_DEBUG) != 0)
1966 			(void) fprintf(stderr, "((%llx & %llx) != %llx) = %d\n",
1967 			    (unsigned long long)v, (unsigned long long)l,
1968 			    (unsigned long long)l, 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