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