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