xref: /dragonfly/contrib/file/src/softmagic.c (revision 655933d6)
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.309 2021/02/05 22:29:07 christos Exp $")
36 #endif	/* lint */
37 
38 #include "magic.h"
39 #include <assert.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <time.h>
44 #include "der.h"
45 
46 private int match(struct magic_set *, struct magic *, uint32_t,
47     const struct buffer *, size_t, int, int, int, uint16_t *,
48     uint16_t *, int *, int *, int *, int *);
49 private int mget(struct magic_set *, struct magic *, const struct buffer *,
50     const unsigned char *, size_t,
51     size_t, unsigned int, int, int, int, uint16_t *,
52     uint16_t *, int *, int *, int *, int *);
53 private int msetoffset(struct magic_set *, struct magic *, struct buffer *,
54     const struct buffer *, 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 int moffset(struct magic_set *, struct magic *, const struct buffer *,
58     int32_t *);
59 private void mdebug(uint32_t, const char *, size_t);
60 private int mcopy(struct magic_set *, union VALUETYPE *, int, int,
61     const unsigned char *, uint32_t, size_t, struct magic *);
62 private int mconvert(struct magic_set *, struct magic *, int);
63 private int print_sep(struct magic_set *, int);
64 private int handle_annotation(struct magic_set *, struct magic *, int);
65 private int cvt_8(union VALUETYPE *, const struct magic *);
66 private int cvt_16(union VALUETYPE *, const struct magic *);
67 private int cvt_32(union VALUETYPE *, const struct magic *);
68 private int cvt_64(union VALUETYPE *, const struct magic *);
69 
70 #define OFFSET_OOB(n, o, i)	((n) < CAST(uint32_t, (o)) || (i) > ((n) - (o)))
71 #define BE64(p) ( \
72     (CAST(uint64_t, (p)->hq[0])<<56)| \
73     (CAST(uint64_t, (p)->hq[1])<<48)| \
74     (CAST(uint64_t, (p)->hq[2])<<40)| \
75     (CAST(uint64_t, (p)->hq[3])<<32)| \
76     (CAST(uint64_t, (p)->hq[4])<<24)| \
77     (CAST(uint64_t, (p)->hq[5])<<16)| \
78     (CAST(uint64_t, (p)->hq[6])<<8)| \
79     (CAST(uint64_t, (p)->hq[7])))
80 #define LE64(p) ( \
81     (CAST(uint64_t, (p)->hq[7])<<56)| \
82     (CAST(uint64_t, (p)->hq[6])<<48)| \
83     (CAST(uint64_t, (p)->hq[5])<<40)| \
84     (CAST(uint64_t, (p)->hq[4])<<32)| \
85     (CAST(uint64_t, (p)->hq[3])<<24)| \
86     (CAST(uint64_t, (p)->hq[2])<<16)| \
87     (CAST(uint64_t, (p)->hq[1])<<8)| \
88     (CAST(uint64_t, (p)->hq[0])))
89 #define LE32(p) ( \
90     (CAST(uint32_t, (p)->hl[3])<<24)| \
91     (CAST(uint32_t, (p)->hl[2])<<16)| \
92     (CAST(uint32_t, (p)->hl[1])<<8)| \
93     (CAST(uint32_t, (p)->hl[0])))
94 #define BE32(p) ( \
95     (CAST(uint32_t, (p)->hl[0])<<24)| \
96     (CAST(uint32_t, (p)->hl[1])<<16)| \
97     (CAST(uint32_t, (p)->hl[2])<<8)| \
98     (CAST(uint32_t, (p)->hl[3])))
99 #define ME32(p) ( \
100     (CAST(uint32_t, (p)->hl[1])<<24)| \
101     (CAST(uint32_t, (p)->hl[0])<<16)| \
102     (CAST(uint32_t, (p)->hl[3])<<8)| \
103     (CAST(uint32_t, (p)->hl[2])))
104 
105 #define BE16(p) ((CAST(uint16_t, (p)->hs[0])<<8)|(CAST(uint16_t, (p)->hs[1])))
106 #define LE16(p) ((CAST(uint16_t, (p)->hs[1])<<8)|(CAST(uint16_t, (p)->hs[0])))
107 #define SEXT(s,v,p) ((s) ? \
108 	CAST(intmax_t, CAST(int##v##_t, p)) : \
109 	CAST(intmax_t, CAST(uint##v##_t, p)))
110 
111 /*
112  * softmagic - lookup one file in parsed, in-memory copy of database
113  * Passed the name and FILE * of one file to be typed.
114  */
115 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
116 protected int
117 file_softmagic(struct magic_set *ms, const struct buffer *b,
118     uint16_t *indir_count, uint16_t *name_count, int mode, int text)
119 {
120 	struct mlist *ml;
121 	int rv, printed_something = 0, need_separator = 0;
122 	uint16_t nc, ic;
123 
124 	if (name_count == NULL) {
125 		nc = 0;
126 		name_count = &nc;
127 	}
128 	if (indir_count == NULL) {
129 		ic = 0;
130 		indir_count = &ic;
131 	}
132 
133 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
134 		if ((rv = match(ms, ml->magic, ml->nmagic, b, 0, mode,
135 		    text, 0, indir_count, name_count,
136 		    &printed_something, &need_separator, NULL, NULL)) != 0)
137 			return rv;
138 
139 	return 0;
140 }
141 
142 #define FILE_FMTDEBUG
143 #ifdef FILE_FMTDEBUG
144 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
145 
146 private const char * __attribute__((__format_arg__(3)))
147 file_fmtcheck(struct magic_set *ms, const char *desc, const char *def,
148 	const char *file, size_t line)
149 {
150 	const char *ptr;
151 
152 	if (strchr(desc, '%') == NULL)
153 		return desc;
154 
155 	ptr = fmtcheck(desc, def);
156 	if (ptr == def)
157 		file_magerror(ms,
158 		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
159 		    " with `%s'", file, line, desc, def);
160 	return ptr;
161 }
162 #else
163 #define F(a, b, c) fmtcheck((b), (c))
164 #endif
165 
166 /*
167  * Go through the whole list, stopping if you find a match.  Process all
168  * the continuations of that match before returning.
169  *
170  * We support multi-level continuations:
171  *
172  *	At any time when processing a successful top-level match, there is a
173  *	current continuation level; it represents the level of the last
174  *	successfully matched continuation.
175  *
176  *	Continuations above that level are skipped as, if we see one, it
177  *	means that the continuation that controls them - i.e, the
178  *	lower-level continuation preceding them - failed to match.
179  *
180  *	Continuations below that level are processed as, if we see one,
181  *	it means we've finished processing or skipping higher-level
182  *	continuations under the control of a successful or unsuccessful
183  *	lower-level continuation, and are now seeing the next lower-level
184  *	continuation and should process it.  The current continuation
185  *	level reverts to the level of the one we're seeing.
186  *
187  *	Continuations at the current level are processed as, if we see
188  *	one, there's no lower-level continuation that may have failed.
189  *
190  *	If a continuation matches, we bump the current continuation level
191  *	so that higher-level continuations are processed.
192  */
193 private int
194 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
195     const struct buffer *b, size_t offset, int mode, int text,
196     int flip, uint16_t *indir_count, uint16_t *name_count,
197     int *printed_something, int *need_separator, int *returnval,
198     int *found_match)
199 {
200 	uint32_t magindex = 0;
201 	unsigned int cont_level = 0;
202 	int found_matchv = 0; /* if a match is found it is set to 1*/
203 	int returnvalv = 0, e;
204 	int firstline = 1; /* a flag to print X\n  X\n- X */
205 	struct buffer bb;
206 	int print = (ms->flags & MAGIC_NODESC) == 0;
207 
208 	/*
209 	 * returnval can be 0 if a match is found, but there was no
210 	 * annotation to be printed.
211 	 */
212 	if (returnval == NULL)
213 		returnval = &returnvalv;
214 	if (found_match == NULL)
215 		found_match = &found_matchv;
216 
217 	if (file_check_mem(ms, cont_level) == -1)
218 		return -1;
219 
220 	for (magindex = 0; magindex < nmagic; magindex++) {
221 		int flush = 0;
222 		struct magic *m = &magic[magindex];
223 
224 		if (m->type != FILE_NAME)
225 		if ((IS_STRING(m->type) &&
226 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
227 		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
228 		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
229 		    (m->flag & mode) != mode) {
230 flush:
231 			/* Skip sub-tests */
232 			while (magindex < nmagic - 1 &&
233 			    magic[magindex + 1].cont_level != 0)
234 				magindex++;
235 			cont_level = 0;
236 			continue; /* Skip to next top-level test*/
237 		}
238 
239 		if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
240 			goto flush;
241 		ms->line = m->lineno;
242 
243 		/* if main entry matches, print it... */
244 		switch (mget(ms, m, b, CAST(const unsigned char *, bb.fbuf),
245 		    bb.flen, offset, cont_level,
246 		    mode, text, flip, indir_count, name_count,
247 		    printed_something, need_separator, returnval, found_match))
248 		{
249 		case -1:
250 			return -1;
251 		case 0:
252 			flush = m->reln != '!';
253 			break;
254 		default:
255 			if (m->type == FILE_INDIRECT) {
256 				*found_match = 1;
257 				*returnval = 1;
258 			}
259 
260 			switch (magiccheck(ms, m)) {
261 			case -1:
262 				return -1;
263 			case 0:
264 				flush++;
265 				break;
266 			default:
267 				flush = 0;
268 				break;
269 			}
270 			break;
271 		}
272 		if (flush) {
273 			/*
274 			 * main entry didn't match,
275 			 * flush its continuations
276 			 */
277 			goto flush;
278 		}
279 
280 		if ((e = handle_annotation(ms, m, firstline)) != 0)
281 		{
282 			*found_match = 1;
283 			*need_separator = 1;
284 			*printed_something = 1;
285 			*returnval = 1;
286 			return e;
287 		}
288 
289 		/*
290 		 * If we are going to print something, we'll need to print
291 		 * a blank before we print something else.
292 		 */
293 		if (*m->desc) {
294 			*found_match = 1;
295 			*returnval = 1;
296 			if (print) {
297 				*need_separator = 1;
298 				*printed_something = 1;
299 				if (print_sep(ms, firstline) == -1)
300 					return -1;
301 				if (mprint(ms, m) == -1)
302 					return -1;
303 			}
304 		}
305 
306 		switch (moffset(ms, m, &bb, &ms->c.li[cont_level].off)) {
307 		case -1:
308 		case 0:
309 			goto flush;
310 		default:
311 			break;
312 		}
313 
314 		/* and any continuations that match */
315 		if (file_check_mem(ms, ++cont_level) == -1)
316 			return -1;
317 
318 		while (magindex + 1 < nmagic &&
319 		    magic[magindex + 1].cont_level != 0) {
320 			m = &magic[++magindex];
321 			ms->line = m->lineno; /* for messages */
322 
323 			if (cont_level < m->cont_level)
324 				continue;
325 			if (cont_level > m->cont_level) {
326 				/*
327 				 * We're at the end of the level
328 				 * "cont_level" continuations.
329 				 */
330 				cont_level = m->cont_level;
331 			}
332 			if (msetoffset(ms, m, &bb, b, offset, cont_level) == -1)
333 				goto flush;
334 			if (m->flag & OFFADD) {
335 				if (cont_level == 0) {
336 					if ((ms->flags & MAGIC_DEBUG) != 0)
337 						fprintf(stderr,
338 						    "direct *zero*"
339 						    " cont_level\n");
340 					return 0;
341 				}
342 				ms->offset +=
343 				    ms->c.li[cont_level - 1].off;
344 			}
345 
346 #ifdef ENABLE_CONDITIONALS
347 			if (m->cond == COND_ELSE ||
348 			    m->cond == COND_ELIF) {
349 				if (ms->c.li[cont_level].last_match == 1)
350 					continue;
351 			}
352 #endif
353 			switch (mget(ms, m, b, CAST(const unsigned char *,
354 			    bb.fbuf), bb.flen, offset,
355 			    cont_level, mode, text, flip, indir_count,
356 			    name_count, printed_something, need_separator,
357 			    returnval, found_match)) {
358 			case -1:
359 				return -1;
360 			case 0:
361 				if (m->reln != '!')
362 					continue;
363 				flush = 1;
364 				break;
365 			default:
366 				if (m->type == FILE_INDIRECT) {
367 					*found_match = 1;
368 					*returnval = 1;
369 				}
370 				flush = 0;
371 				break;
372 			}
373 
374 			switch (flush ? 1 : magiccheck(ms, m)) {
375 			case -1:
376 				return -1;
377 			case 0:
378 #ifdef ENABLE_CONDITIONALS
379 				ms->c.li[cont_level].last_match = 0;
380 #endif
381 				break;
382 			default:
383 #ifdef ENABLE_CONDITIONALS
384 				ms->c.li[cont_level].last_match = 1;
385 #endif
386 				if (m->type == FILE_CLEAR)
387 					ms->c.li[cont_level].got_match = 0;
388 				else if (ms->c.li[cont_level].got_match) {
389 					if (m->type == FILE_DEFAULT)
390 						break;
391 				} else
392 					ms->c.li[cont_level].got_match = 1;
393 
394 				if ((e = handle_annotation(ms, m, firstline))
395 				    != 0) {
396 					*found_match = 1;
397 					*need_separator = 1;
398 					*printed_something = 1;
399 					*returnval = 1;
400 					return e;
401 				}
402 				if (*m->desc) {
403 					*found_match = 1;
404 					*returnval = 1;
405 				}
406 				if (print && *m->desc) {
407 					/*
408 					 * This continuation matched.  Print
409 					 * its message, with a blank before it
410 					 * if the previous item printed and
411 					 * this item isn't empty.
412 					 */
413 					/*
414 					 * If we are going to print something,
415 					 * make sure that we have a separator
416 					 * first.
417 					 */
418 					if (!*printed_something) {
419 						*printed_something = 1;
420 						if (print_sep(ms, firstline)
421 						    == -1)
422 							return -1;
423 					}
424 					/* space if previous printed */
425 					if (*need_separator
426 					    && (m->flag & NOSPACE) == 0) {
427 						if (file_printf(ms, " ") == -1)
428 							return -1;
429 					}
430 					*need_separator = 0;
431 					if (mprint(ms, m) == -1)
432 						return -1;
433 					*need_separator = 1;
434 				}
435 
436 				switch (moffset(ms, m, &bb,
437 				    &ms->c.li[cont_level].off)) {
438 				case -1:
439 				case 0:
440 					flush = 1;
441 					cont_level--;
442 					break;
443 				default:
444 					break;
445 				}
446 
447 				/*
448 				 * If we see any continuations
449 				 * at a higher level,
450 				 * process them.
451 				 */
452 				if (file_check_mem(ms, ++cont_level) == -1)
453 					return -1;
454 				break;
455 			}
456 		}
457 		if (*printed_something) {
458 			firstline = 0;
459 		}
460 		if (*found_match) {
461 			if ((ms->flags & MAGIC_CONTINUE) == 0)
462 				goto out;
463 			// So that we print a separator
464 			*printed_something = 0;
465 			firstline = 0;
466 		}
467 		cont_level = 0;
468 	}
469 out:
470 	/*
471 	 * If we are not printing (we are doing mime etc.)
472 	 * and we did not find a mime entry, and we are at 0 level
473 	 * we want to return 0 so that the default mime printer
474 	 * takes over and prints "application/octet-stream"
475 	 */
476 	if (! print && ! *printed_something && ! *name_count)
477 		return 0;
478 	return *returnval;  /* This is hit if -k is set or there is no match */
479 }
480 
481 private int
482 check_fmt(struct magic_set *ms, const char *fmt)
483 {
484 	file_regex_t rx;
485 	int rc, rv = -1;
486 
487 	if (strchr(fmt, '%') == NULL)
488 		return 0;
489 
490 	rc = file_regcomp(&rx, "%[-0-9\\.]*s", REG_EXTENDED|REG_NOSUB);
491 	if (rc) {
492 		file_regerror(&rx, rc, ms);
493 	} else {
494 		rc = file_regexec(&rx, fmt, 0, 0, 0);
495 		rv = !rc;
496 	}
497 	file_regfree(&rx);
498 	return rv;
499 }
500 
501 #if !defined(HAVE_STRNDUP) || defined(__aiws__) || defined(_AIX)
502 # if defined(__aiws__) || defined(_AIX)
503 #  define strndup aix_strndup	/* aix is broken */
504 # endif
505 char *strndup(const char *, size_t);
506 
507 char *
508 strndup(const char *str, size_t n)
509 {
510 	size_t len;
511 	char *copy;
512 
513 	for (len = 0; len < n && str[len]; len++)
514 		continue;
515 	if ((copy = malloc(len + 1)) == NULL)
516 		return NULL;
517 	(void)memcpy(copy, str, len);
518 	copy[len] = '\0';
519 	return copy;
520 }
521 #endif /* HAVE_STRNDUP */
522 
523 static int
524 varexpand(struct magic_set *ms, char *buf, size_t len, const char *str)
525 {
526 	const char *ptr, *sptr, *e, *t, *ee, *et;
527 	size_t l;
528 
529 	for (sptr = str; (ptr = strstr(sptr, "${")) != NULL;) {
530 		l = CAST(size_t, ptr - sptr);
531 		if (l >= len)
532 			return -1;
533 		memcpy(buf, sptr, l);
534 		buf += l;
535 		len -= l;
536 		ptr += 2;
537 		if (!*ptr || ptr[1] != '?')
538 			return -1;
539 		for (et = t = ptr + 2; *et && *et != ':'; et++)
540 			continue;
541 		if (*et != ':')
542 			return -1;
543 		for (ee = e = et + 1; *ee && *ee != '}'; ee++)
544 			continue;
545 		if (*ee != '}')
546 			return -1;
547 		switch (*ptr) {
548 		case 'x':
549 			if (ms->mode & 0111) {
550 				ptr = t;
551 				l = et - t;
552 			} else {
553 				ptr = e;
554 				l = ee - e;
555 			}
556 			break;
557 		default:
558 			return -1;
559 		}
560 		if (l >= len)
561 			return -1;
562 		memcpy(buf, ptr, l);
563 		buf += l;
564 		len -= l;
565 		sptr = ee + 1;
566 	}
567 
568 	l = strlen(sptr);
569 	if (l >= len)
570 		return -1;
571 
572 	memcpy(buf, sptr, l);
573 	buf[l] = '\0';
574 	return 0;
575 }
576 
577 
578 private int32_t
579 mprint(struct magic_set *ms, struct magic *m)
580 {
581 	uint64_t v;
582 	float vf;
583 	double vd;
584 	int64_t t = 0;
585  	char buf[128], tbuf[26], sbuf[512], ebuf[512];
586 	const char *desc;
587 	union VALUETYPE *p = &ms->ms_value;
588 
589 	if (varexpand(ms, ebuf, sizeof(ebuf), m->desc) == -1)
590 		desc = m->desc;
591 	else
592 		desc = ebuf;
593 
594 #define	PRINTER(value, format, stype, utype)	\
595 	v = file_signextend(ms, m, CAST(uint64_t, value)); \
596 	switch (check_fmt(ms, desc)) { \
597 	case -1: \
598 		return -1; \
599 	case 1: \
600 		if (m->flag & UNSIGNED) { \
601 			(void)snprintf(buf, sizeof(buf), "%" format "u", \
602 			    CAST(utype, v)); \
603 		} else { \
604 			(void)snprintf(buf, sizeof(buf), "%" format "d", \
605 			    CAST(stype, v)); \
606 		} \
607 		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1) \
608 			return -1; \
609 		break; \
610 	default: \
611 		if (m->flag & UNSIGNED) { \
612 		       if (file_printf(ms, F(ms, desc, "%" format "u"), \
613 			   CAST(utype, v)) == -1) \
614 			   return -1; \
615 		} else { \
616 		       if (file_printf(ms, F(ms, desc, "%" format "d"), \
617 			   CAST(stype, v)) == -1) \
618 			   return -1; \
619 		} \
620 		break; \
621 	} \
622 	t = ms->offset + sizeof(stype); \
623 	break
624 
625   	switch (m->type) {
626   	case FILE_BYTE:
627 		PRINTER(p->b, "", int8_t, uint8_t);
628 
629   	case FILE_SHORT:
630   	case FILE_BESHORT:
631   	case FILE_LESHORT:
632 		PRINTER(p->h, "", int16_t, uint16_t);
633 
634   	case FILE_LONG:
635   	case FILE_BELONG:
636   	case FILE_LELONG:
637   	case FILE_MELONG:
638 		PRINTER(p->l, "", int32_t, uint32_t);
639   		break;
640 
641   	case FILE_QUAD:
642   	case FILE_BEQUAD:
643   	case FILE_LEQUAD:
644 	case FILE_OFFSET:
645 		PRINTER(p->q, INT64_T_FORMAT, long long, unsigned long long);
646   		break;
647 
648   	case FILE_STRING:
649   	case FILE_PSTRING:
650   	case FILE_BESTRING16:
651   	case FILE_LESTRING16:
652 		if (m->reln == '=' || m->reln == '!') {
653 			if (file_printf(ms, F(ms, desc, "%s"),
654 			    file_printable(sbuf, sizeof(sbuf), m->value.s,
655 			    sizeof(m->value.s))) == -1)
656 				return -1;
657 			t = ms->offset + m->vallen;
658 		}
659 		else {
660 			char *str = p->s;
661 
662 			/* compute t before we mangle the string? */
663 			t = ms->offset + strlen(str);
664 
665 			if (*m->value.s == '\0')
666 				str[strcspn(str, "\r\n")] = '\0';
667 
668 			if (m->str_flags & STRING_TRIM)
669 				str = file_strtrim(str);
670 
671 			if (file_printf(ms, F(ms, desc, "%s"),
672 			    file_printable(sbuf, sizeof(sbuf), str,
673 				sizeof(p->s) - (str - p->s))) == -1)
674 				return -1;
675 
676 			if (m->type == FILE_PSTRING) {
677 				size_t l = file_pstring_length_size(ms, m);
678 				if (l == FILE_BADSIZE)
679 					return -1;
680 				t += l;
681 			}
682 		}
683 		break;
684 
685 	case FILE_DATE:
686 	case FILE_BEDATE:
687 	case FILE_LEDATE:
688 	case FILE_MEDATE:
689 		if (file_printf(ms, F(ms, desc, "%s"),
690 		    file_fmttime(tbuf, sizeof(tbuf), p->l, 0)) == -1)
691 			return -1;
692 		t = ms->offset + sizeof(uint32_t);
693 		break;
694 
695 	case FILE_LDATE:
696 	case FILE_BELDATE:
697 	case FILE_LELDATE:
698 	case FILE_MELDATE:
699 		if (file_printf(ms, F(ms, desc, "%s"),
700 		    file_fmttime(tbuf, sizeof(tbuf), p->l, FILE_T_LOCAL)) == -1)
701 			return -1;
702 		t = ms->offset + sizeof(uint32_t);
703 		break;
704 
705 	case FILE_QDATE:
706 	case FILE_BEQDATE:
707 	case FILE_LEQDATE:
708 		if (file_printf(ms, F(ms, desc, "%s"),
709 		    file_fmttime(tbuf, sizeof(tbuf), p->q, 0)) == -1)
710 			return -1;
711 		t = ms->offset + sizeof(uint64_t);
712 		break;
713 
714 	case FILE_QLDATE:
715 	case FILE_BEQLDATE:
716 	case FILE_LEQLDATE:
717 		if (file_printf(ms, F(ms, desc, "%s"),
718 		    file_fmttime(tbuf, sizeof(tbuf), p->q, FILE_T_LOCAL)) == -1)
719 			return -1;
720 		t = ms->offset + sizeof(uint64_t);
721 		break;
722 
723 	case FILE_QWDATE:
724 	case FILE_BEQWDATE:
725 	case FILE_LEQWDATE:
726 		if (file_printf(ms, F(ms, desc, "%s"),
727 		    file_fmttime(tbuf, sizeof(tbuf), p->q, FILE_T_WINDOWS))
728 		    == -1)
729 			return -1;
730 		t = ms->offset + sizeof(uint64_t);
731 		break;
732 
733 	case FILE_FLOAT:
734 	case FILE_BEFLOAT:
735 	case FILE_LEFLOAT:
736 		vf = p->f;
737 		switch (check_fmt(ms, desc)) {
738 		case -1:
739 			return -1;
740 		case 1:
741 			(void)snprintf(buf, sizeof(buf), "%g", vf);
742 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
743 				return -1;
744 			break;
745 		default:
746 			if (file_printf(ms, F(ms, desc, "%g"), vf) == -1)
747 				return -1;
748 			break;
749 		}
750 		t = ms->offset + sizeof(float);
751   		break;
752 
753 	case FILE_DOUBLE:
754 	case FILE_BEDOUBLE:
755 	case FILE_LEDOUBLE:
756 		vd = p->d;
757 		switch (check_fmt(ms, desc)) {
758 		case -1:
759 			return -1;
760 		case 1:
761 			(void)snprintf(buf, sizeof(buf), "%g", vd);
762 			if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
763 				return -1;
764 			break;
765 		default:
766 			if (file_printf(ms, F(ms, desc, "%g"), vd) == -1)
767 				return -1;
768 			break;
769 		}
770 		t = ms->offset + sizeof(double);
771   		break;
772 
773 	case FILE_SEARCH:
774 	case FILE_REGEX: {
775 		char *cp, *scp;
776 		int rval;
777 
778 		cp = strndup(RCAST(const char *, ms->search.s),
779 		    ms->search.rm_len);
780 		if (cp == NULL) {
781 			file_oomem(ms, ms->search.rm_len);
782 			return -1;
783 		}
784 		scp = (m->str_flags & STRING_TRIM) ? file_strtrim(cp) : cp;
785 
786 		rval = file_printf(ms, F(ms, desc, "%s"),
787 		    file_printable(sbuf, sizeof(sbuf), scp, ms->search.rm_len));
788 		free(cp);
789 
790 		if (rval == -1)
791 			return -1;
792 
793 		if ((m->str_flags & REGEX_OFFSET_START))
794 			t = ms->search.offset;
795 		else
796 			t = ms->search.offset + ms->search.rm_len;
797 		break;
798 	}
799 
800 	case FILE_DEFAULT:
801 	case FILE_CLEAR:
802 	  	if (file_printf(ms, "%s", m->desc) == -1)
803 			return -1;
804 		t = ms->offset;
805 		break;
806 
807 	case FILE_INDIRECT:
808 	case FILE_USE:
809 	case FILE_NAME:
810 		t = ms->offset;
811 		break;
812 	case FILE_DER:
813 		if (file_printf(ms, F(ms, desc, "%s"),
814 		    file_printable(sbuf, sizeof(sbuf), ms->ms_value.s,
815 			sizeof(ms->ms_value.s))) == -1)
816 			return -1;
817 		t = ms->offset;
818 		break;
819 	case FILE_GUID:
820 		(void) file_print_guid(buf, sizeof(buf), ms->ms_value.guid);
821 		if (file_printf(ms, F(ms, desc, "%s"), buf) == -1)
822 			return -1;
823 		t = ms->offset;
824 		break;
825 	default:
826 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
827 		return -1;
828 	}
829 	return CAST(int32_t, t);
830 }
831 
832 private int
833 moffset(struct magic_set *ms, struct magic *m, const struct buffer *b,
834     int32_t *op)
835 {
836 	size_t nbytes = b->flen;
837 	int32_t o;
838 
839   	switch (m->type) {
840   	case FILE_BYTE:
841 		o = CAST(int32_t, (ms->offset + sizeof(char)));
842 		break;
843 
844   	case FILE_SHORT:
845   	case FILE_BESHORT:
846   	case FILE_LESHORT:
847 		o = CAST(int32_t, (ms->offset + sizeof(short)));
848 		break;
849 
850   	case FILE_LONG:
851   	case FILE_BELONG:
852   	case FILE_LELONG:
853   	case FILE_MELONG:
854 		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
855 		break;
856 
857   	case FILE_QUAD:
858   	case FILE_BEQUAD:
859   	case FILE_LEQUAD:
860 		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
861 		break;
862 
863   	case FILE_STRING:
864   	case FILE_PSTRING:
865   	case FILE_BESTRING16:
866   	case FILE_LESTRING16:
867 		if (m->reln == '=' || m->reln == '!') {
868 			o = ms->offset + m->vallen;
869 		} else {
870 			union VALUETYPE *p = &ms->ms_value;
871 
872 			if (*m->value.s == '\0')
873 				p->s[strcspn(p->s, "\r\n")] = '\0';
874 			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
875 			if (m->type == FILE_PSTRING) {
876 				size_t l = file_pstring_length_size(ms, m);
877 				if (l == FILE_BADSIZE)
878 					return -1;
879 				o += CAST(uint32_t, l);
880 			}
881 		}
882 		break;
883 
884 	case FILE_DATE:
885 	case FILE_BEDATE:
886 	case FILE_LEDATE:
887 	case FILE_MEDATE:
888 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
889 		break;
890 
891 	case FILE_LDATE:
892 	case FILE_BELDATE:
893 	case FILE_LELDATE:
894 	case FILE_MELDATE:
895 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
896 		break;
897 
898 	case FILE_QDATE:
899 	case FILE_BEQDATE:
900 	case FILE_LEQDATE:
901 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
902 		break;
903 
904 	case FILE_QLDATE:
905 	case FILE_BEQLDATE:
906 	case FILE_LEQLDATE:
907 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
908 		break;
909 
910   	case FILE_FLOAT:
911   	case FILE_BEFLOAT:
912   	case FILE_LEFLOAT:
913 		o = CAST(int32_t, (ms->offset + sizeof(float)));
914 		break;
915 
916   	case FILE_DOUBLE:
917   	case FILE_BEDOUBLE:
918   	case FILE_LEDOUBLE:
919 		o = CAST(int32_t, (ms->offset + sizeof(double)));
920 		break;
921 
922 	case FILE_REGEX:
923 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
924 			o = CAST(int32_t, ms->search.offset);
925 		else
926 			o = CAST(int32_t,
927 			    (ms->search.offset + ms->search.rm_len));
928 		break;
929 
930 	case FILE_SEARCH:
931 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
932 			o = CAST(int32_t, ms->search.offset);
933 		else
934 			o = CAST(int32_t, (ms->search.offset + m->vallen));
935 		break;
936 
937 	case FILE_CLEAR:
938 	case FILE_DEFAULT:
939 	case FILE_INDIRECT:
940 	case FILE_OFFSET:
941 	case FILE_USE:
942 		o = ms->offset;
943 		break;
944 
945 	case FILE_DER:
946 		o = der_offs(ms, m, nbytes);
947 		if (o == -1 || CAST(size_t, o) > nbytes) {
948 			if ((ms->flags & MAGIC_DEBUG) != 0) {
949 				(void)fprintf(stderr,
950 				    "Bad DER offset %d nbytes=%"
951 				    SIZE_T_FORMAT "u", o, nbytes);
952 			}
953 			*op = 0;
954 			return 0;
955 		}
956 		break;
957 
958 	case FILE_GUID:
959 		o = CAST(int32_t, (ms->offset + 2 * sizeof(uint64_t)));
960 		break;
961 
962 	default:
963 		o = 0;
964 		break;
965 	}
966 
967 	if (CAST(size_t, o) > nbytes) {
968 #if 0
969 		file_error(ms, 0, "Offset out of range %" SIZE_T_FORMAT
970 		    "u > %" SIZE_T_FORMAT "u", (size_t)o, nbytes);
971 #endif
972 		return -1;
973 	}
974 	*op = o;
975 	return 1;
976 }
977 
978 private uint32_t
979 cvt_id3(struct magic_set *ms, uint32_t v)
980 {
981 	v = ((((v >>  0) & 0x7f) <<  0) |
982 	     (((v >>  8) & 0x7f) <<  7) |
983 	     (((v >> 16) & 0x7f) << 14) |
984 	     (((v >> 24) & 0x7f) << 21));
985 	if ((ms->flags & MAGIC_DEBUG) != 0)
986 		fprintf(stderr, "id3 offs=%u\n", v);
987 	return v;
988 }
989 
990 private int
991 cvt_flip(int type, int flip)
992 {
993 	if (flip == 0)
994 		return type;
995 	switch (type) {
996 	case FILE_BESHORT:
997 		return FILE_LESHORT;
998 	case FILE_BELONG:
999 		return FILE_LELONG;
1000 	case FILE_BEDATE:
1001 		return FILE_LEDATE;
1002 	case FILE_BELDATE:
1003 		return FILE_LELDATE;
1004 	case FILE_BEQUAD:
1005 		return FILE_LEQUAD;
1006 	case FILE_BEQDATE:
1007 		return FILE_LEQDATE;
1008 	case FILE_BEQLDATE:
1009 		return FILE_LEQLDATE;
1010 	case FILE_BEQWDATE:
1011 		return FILE_LEQWDATE;
1012 	case FILE_LESHORT:
1013 		return FILE_BESHORT;
1014 	case FILE_LELONG:
1015 		return FILE_BELONG;
1016 	case FILE_LEDATE:
1017 		return FILE_BEDATE;
1018 	case FILE_LELDATE:
1019 		return FILE_BELDATE;
1020 	case FILE_LEQUAD:
1021 		return FILE_BEQUAD;
1022 	case FILE_LEQDATE:
1023 		return FILE_BEQDATE;
1024 	case FILE_LEQLDATE:
1025 		return FILE_BEQLDATE;
1026 	case FILE_LEQWDATE:
1027 		return FILE_BEQWDATE;
1028 	case FILE_BEFLOAT:
1029 		return FILE_LEFLOAT;
1030 	case FILE_LEFLOAT:
1031 		return FILE_BEFLOAT;
1032 	case FILE_BEDOUBLE:
1033 		return FILE_LEDOUBLE;
1034 	case FILE_LEDOUBLE:
1035 		return FILE_BEDOUBLE;
1036 	default:
1037 		return type;
1038 	}
1039 }
1040 #define DO_CVT(fld, type) \
1041 	if (m->num_mask) \
1042 		switch (m->mask_op & FILE_OPS_MASK) { \
1043 		case FILE_OPAND: \
1044 			p->fld &= CAST(type, m->num_mask); \
1045 			break; \
1046 		case FILE_OPOR: \
1047 			p->fld |= CAST(type, m->num_mask); \
1048 			break; \
1049 		case FILE_OPXOR: \
1050 			p->fld ^= CAST(type, m->num_mask); \
1051 			break; \
1052 		case FILE_OPADD: \
1053 			p->fld += CAST(type, m->num_mask); \
1054 			break; \
1055 		case FILE_OPMINUS: \
1056 			p->fld -= CAST(type, m->num_mask); \
1057 			break; \
1058 		case FILE_OPMULTIPLY: \
1059 			p->fld *= CAST(type, m->num_mask); \
1060 			break; \
1061 		case FILE_OPDIVIDE: \
1062 			if (CAST(type, m->num_mask) == 0) \
1063 				return -1; \
1064 			p->fld /= CAST(type, m->num_mask); \
1065 			break; \
1066 		case FILE_OPMODULO: \
1067 			if (CAST(type, m->num_mask) == 0) \
1068 				return -1; \
1069 			p->fld %= CAST(type, m->num_mask); \
1070 			break; \
1071 		} \
1072 	if (m->mask_op & FILE_OPINVERSE) \
1073 		p->fld = ~p->fld \
1074 
1075 private int
1076 cvt_8(union VALUETYPE *p, const struct magic *m)
1077 {
1078 	DO_CVT(b, uint8_t);
1079 	return 0;
1080 }
1081 
1082 private int
1083 cvt_16(union VALUETYPE *p, const struct magic *m)
1084 {
1085 	DO_CVT(h, uint16_t);
1086 	return 0;
1087 }
1088 
1089 private int
1090 cvt_32(union VALUETYPE *p, const struct magic *m)
1091 {
1092 	DO_CVT(l, uint32_t);
1093 	return 0;
1094 }
1095 
1096 private int
1097 cvt_64(union VALUETYPE *p, const struct magic *m)
1098 {
1099 	DO_CVT(q, uint64_t);
1100 	return 0;
1101 }
1102 
1103 #define DO_CVT2(fld, type) \
1104 	if (m->num_mask) \
1105 		switch (m->mask_op & FILE_OPS_MASK) { \
1106 		case FILE_OPADD: \
1107 			p->fld += CAST(type, m->num_mask); \
1108 			break; \
1109 		case FILE_OPMINUS: \
1110 			p->fld -= CAST(type, m->num_mask); \
1111 			break; \
1112 		case FILE_OPMULTIPLY: \
1113 			p->fld *= CAST(type, m->num_mask); \
1114 			break; \
1115 		case FILE_OPDIVIDE: \
1116 			if (CAST(type, m->num_mask) == 0) \
1117 				return -1; \
1118 			p->fld /= CAST(type, m->num_mask); \
1119 			break; \
1120 		} \
1121 
1122 private int
1123 cvt_float(union VALUETYPE *p, const struct magic *m)
1124 {
1125 	DO_CVT2(f, float);
1126 	return 0;
1127 }
1128 
1129 private int
1130 cvt_double(union VALUETYPE *p, const struct magic *m)
1131 {
1132 	DO_CVT2(d, double);
1133 	return 0;
1134 }
1135 
1136 /*
1137  * Convert the byte order of the data we are looking at
1138  * While we're here, let's apply the mask operation
1139  * (unless you have a better idea)
1140  */
1141 private int
1142 mconvert(struct magic_set *ms, struct magic *m, int flip)
1143 {
1144 	union VALUETYPE *p = &ms->ms_value;
1145 
1146 	switch (cvt_flip(m->type, flip)) {
1147 	case FILE_BYTE:
1148 		if (cvt_8(p, m) == -1)
1149 			goto out;
1150 		return 1;
1151 	case FILE_SHORT:
1152 		if (cvt_16(p, m) == -1)
1153 			goto out;
1154 		return 1;
1155 	case FILE_LONG:
1156 	case FILE_DATE:
1157 	case FILE_LDATE:
1158 		if (cvt_32(p, m) == -1)
1159 			goto out;
1160 		return 1;
1161 	case FILE_QUAD:
1162 	case FILE_QDATE:
1163 	case FILE_QLDATE:
1164 	case FILE_QWDATE:
1165 	case FILE_OFFSET:
1166 		if (cvt_64(p, m) == -1)
1167 			goto out;
1168 		return 1;
1169 	case FILE_STRING:
1170 	case FILE_BESTRING16:
1171 	case FILE_LESTRING16: {
1172 		/* Null terminate and eat *trailing* return */
1173 		p->s[sizeof(p->s) - 1] = '\0';
1174 		return 1;
1175 	}
1176 	case FILE_PSTRING: {
1177 		char *ptr1, *ptr2;
1178 		size_t len, sz = file_pstring_length_size(ms, m);
1179 		if (sz == FILE_BADSIZE)
1180 			return 0;
1181 		ptr1 = p->s;
1182 		ptr2 = ptr1 + sz;
1183 		len = file_pstring_get_length(ms, m, ptr1);
1184 		if (len == FILE_BADSIZE)
1185 			return 0;
1186 		sz = sizeof(p->s) - sz; /* maximum length of string */
1187 		if (len >= sz) {
1188 			/*
1189 			 * The size of the pascal string length (sz)
1190 			 * is 1, 2, or 4. We need at least 1 byte for NUL
1191 			 * termination, but we've already truncated the
1192 			 * string by p->s, so we need to deduct sz.
1193 			 * Because we can use one of the bytes of the length
1194 			 * after we shifted as NUL termination.
1195 			 */
1196 			len = sz;
1197 		}
1198 		while (len--)
1199 			*ptr1++ = *ptr2++;
1200 		*ptr1 = '\0';
1201 		return 1;
1202 	}
1203 	case FILE_BESHORT:
1204 		p->h = CAST(short, BE16(p));
1205 		if (cvt_16(p, m) == -1)
1206 			goto out;
1207 		return 1;
1208 	case FILE_BELONG:
1209 	case FILE_BEDATE:
1210 	case FILE_BELDATE:
1211 		p->l = CAST(int32_t, BE32(p));
1212 		if (cvt_32(p, m) == -1)
1213 			goto out;
1214 		return 1;
1215 	case FILE_BEQUAD:
1216 	case FILE_BEQDATE:
1217 	case FILE_BEQLDATE:
1218 	case FILE_BEQWDATE:
1219 		p->q = CAST(uint64_t, BE64(p));
1220 		if (cvt_64(p, m) == -1)
1221 			goto out;
1222 		return 1;
1223 	case FILE_LESHORT:
1224 		p->h = CAST(short, LE16(p));
1225 		if (cvt_16(p, m) == -1)
1226 			goto out;
1227 		return 1;
1228 	case FILE_LELONG:
1229 	case FILE_LEDATE:
1230 	case FILE_LELDATE:
1231 		p->l = CAST(int32_t, LE32(p));
1232 		if (cvt_32(p, m) == -1)
1233 			goto out;
1234 		return 1;
1235 	case FILE_LEQUAD:
1236 	case FILE_LEQDATE:
1237 	case FILE_LEQLDATE:
1238 	case FILE_LEQWDATE:
1239 		p->q = CAST(uint64_t, LE64(p));
1240 		if (cvt_64(p, m) == -1)
1241 			goto out;
1242 		return 1;
1243 	case FILE_MELONG:
1244 	case FILE_MEDATE:
1245 	case FILE_MELDATE:
1246 		p->l = CAST(int32_t, ME32(p));
1247 		if (cvt_32(p, m) == -1)
1248 			goto out;
1249 		return 1;
1250 	case FILE_FLOAT:
1251 		if (cvt_float(p, m) == -1)
1252 			goto out;
1253 		return 1;
1254 	case FILE_BEFLOAT:
1255 		p->l = BE32(p);
1256 		if (cvt_float(p, m) == -1)
1257 			goto out;
1258 		return 1;
1259 	case FILE_LEFLOAT:
1260 		p->l = LE32(p);
1261 		if (cvt_float(p, m) == -1)
1262 			goto out;
1263 		return 1;
1264 	case FILE_DOUBLE:
1265 		if (cvt_double(p, m) == -1)
1266 			goto out;
1267 		return 1;
1268 	case FILE_BEDOUBLE:
1269 		p->q = BE64(p);
1270 		if (cvt_double(p, m) == -1)
1271 			goto out;
1272 		return 1;
1273 	case FILE_LEDOUBLE:
1274 		p->q = LE64(p);
1275 		if (cvt_double(p, m) == -1)
1276 			goto out;
1277 		return 1;
1278 	case FILE_REGEX:
1279 	case FILE_SEARCH:
1280 	case FILE_DEFAULT:
1281 	case FILE_CLEAR:
1282 	case FILE_NAME:
1283 	case FILE_USE:
1284 	case FILE_DER:
1285 	case FILE_GUID:
1286 		return 1;
1287 	default:
1288 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1289 		return 0;
1290 	}
1291 out:
1292 	file_magerror(ms, "zerodivide in mconvert()");
1293 	return 0;
1294 }
1295 
1296 
1297 private void
1298 mdebug(uint32_t offset, const char *str, size_t len)
1299 {
1300 	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1301 	file_showstr(stderr, str, len);
1302 	(void) fputc('\n', stderr);
1303 	(void) fputc('\n', stderr);
1304 }
1305 
1306 private int
1307 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1308     const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1309 {
1310 	/*
1311 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1312 	 * anything, but setup pointers into the source
1313 	 */
1314 	if (indir == 0) {
1315 		switch (type) {
1316 		case FILE_DER:
1317 		case FILE_SEARCH:
1318 			if (offset > nbytes)
1319 				offset = CAST(uint32_t, nbytes);
1320 			ms->search.s = RCAST(const char *, s) + offset;
1321 			ms->search.s_len = nbytes - offset;
1322 			ms->search.offset = offset;
1323 			return 0;
1324 
1325 		case FILE_REGEX: {
1326 			const char *b;
1327 			const char *c;
1328 			const char *last;	/* end of search region */
1329 			const char *buf;	/* start of search region */
1330 			const char *end;
1331 			size_t lines, linecnt, bytecnt;
1332 
1333 			if (s == NULL || nbytes < offset) {
1334 				ms->search.s_len = 0;
1335 				ms->search.s = NULL;
1336 				return 0;
1337 			}
1338 
1339 			if (m->str_flags & REGEX_LINE_COUNT) {
1340 				linecnt = m->str_range;
1341 				bytecnt = linecnt * 80;
1342 			} else {
1343 				linecnt = 0;
1344 				bytecnt = m->str_range;
1345 			}
1346 
1347 			if (bytecnt == 0 || bytecnt > nbytes - offset)
1348 				bytecnt = nbytes - offset;
1349 			if (bytecnt > ms->regex_max)
1350 				bytecnt = ms->regex_max;
1351 
1352 			buf = RCAST(const char *, s) + offset;
1353 			end = last = RCAST(const char *, s) + bytecnt + offset;
1354 			/* mget() guarantees buf <= last */
1355 			for (lines = linecnt, b = buf; lines && b < end &&
1356 			     ((b = CAST(const char *,
1357 				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1358 			     || (b = CAST(const char *,
1359 				 memchr(c, '\r', CAST(size_t, (end - c))))));
1360 			     lines--, b++) {
1361 				if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1362 					b++;
1363 				if (b < end - 1 && b[0] == '\n')
1364 					b++;
1365 				last = b;
1366 			}
1367 			if (lines)
1368 				last = end;
1369 
1370 			ms->search.s = buf;
1371 			ms->search.s_len = last - buf;
1372 			ms->search.offset = offset;
1373 			ms->search.rm_len = 0;
1374 			return 0;
1375 		}
1376 		case FILE_BESTRING16:
1377 		case FILE_LESTRING16: {
1378 			const unsigned char *src = s + offset;
1379 			const unsigned char *esrc = s + nbytes;
1380 			char *dst = p->s;
1381 			char *edst = &p->s[sizeof(p->s) - 1];
1382 
1383 			if (type == FILE_BESTRING16)
1384 				src++;
1385 
1386 			/* check that offset is within range */
1387 			if (offset >= nbytes)
1388 				break;
1389 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1390 				if (dst < edst)
1391 					*dst = *src;
1392 				else
1393 					break;
1394 				if (*dst == '\0') {
1395 					if (type == FILE_BESTRING16 ?
1396 					    *(src - 1) != '\0' :
1397 					    ((src + 1 < esrc) &&
1398 					    *(src + 1) != '\0'))
1399 						*dst = ' ';
1400 				}
1401 			}
1402 			*edst = '\0';
1403 			return 0;
1404 		}
1405 		case FILE_STRING:	/* XXX - these two should not need */
1406 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1407 		default:
1408 			break;
1409 		}
1410 	}
1411 
1412 	if (type == FILE_OFFSET) {
1413 		(void)memset(p, '\0', sizeof(*p));
1414 		p->q = offset;
1415 		return 0;
1416 	}
1417 
1418 	if (offset >= nbytes) {
1419 		(void)memset(p, '\0', sizeof(*p));
1420 		return 0;
1421 	}
1422 	if (nbytes - offset < sizeof(*p))
1423 		nbytes = nbytes - offset;
1424 	else
1425 		nbytes = sizeof(*p);
1426 
1427 	(void)memcpy(p, s + offset, nbytes);
1428 
1429 	/*
1430 	 * the usefulness of padding with zeroes eludes me, it
1431 	 * might even cause problems
1432 	 */
1433 	if (nbytes < sizeof(*p))
1434 		(void)memset(RCAST(char *, RCAST(void *, p)) + nbytes, '\0',
1435 		    sizeof(*p) - nbytes);
1436 	return 0;
1437 }
1438 
1439 private uint32_t
1440 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1441 {
1442 	intmax_t offset = 0;
1443 	if (off) {
1444 		switch (m->in_op & FILE_OPS_MASK) {
1445 		case FILE_OPAND:
1446 			offset = lhs & off;
1447 			break;
1448 		case FILE_OPOR:
1449 			offset = lhs | off;
1450 			break;
1451 		case FILE_OPXOR:
1452 			offset = lhs ^ off;
1453 			break;
1454 		case FILE_OPADD:
1455 			offset = lhs + off;
1456 			break;
1457 		case FILE_OPMINUS:
1458 			offset = lhs - off;
1459 			break;
1460 		case FILE_OPMULTIPLY:
1461 			offset = lhs * off;
1462 			break;
1463 		case FILE_OPDIVIDE:
1464 			offset = lhs / off;
1465 			break;
1466 		case FILE_OPMODULO:
1467 			offset = lhs % off;
1468 			break;
1469 		}
1470 	} else
1471 		offset = lhs;
1472 	if (m->in_op & FILE_OPINVERSE)
1473 		offset = ~offset;
1474 
1475 	return CAST(uint32_t, offset);
1476 }
1477 
1478 private int
1479 msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
1480     const struct buffer *b, size_t o, unsigned int cont_level)
1481 {
1482 	int32_t offset;
1483 	if (m->flag & OFFNEGATIVE) {
1484 		offset = -m->offset;
1485 		if (cont_level > 0) {
1486 			if (m->flag & (OFFADD|INDIROFFADD))
1487 				goto normal;
1488 #if 0
1489 			file_error(ms, 0, "negative offset %d at continuation"
1490 			    "level %u", m->offset, cont_level);
1491 			return -1;
1492 #endif
1493 		}
1494 		if (buffer_fill(b) == -1)
1495 			return -1;
1496 		if (o != 0) {
1497 			// Not yet!
1498 			file_magerror(ms, "non zero offset %" SIZE_T_FORMAT
1499 			    "u at level %u", o, cont_level);
1500 			return -1;
1501 		}
1502 		if (CAST(size_t, m->offset) > b->elen)
1503 			return -1;
1504 		buffer_init(bb, -1, NULL, b->ebuf, b->elen);
1505 		ms->eoffset = ms->offset = CAST(int32_t, b->elen - m->offset);
1506 	} else {
1507 		offset = m->offset;
1508 		if (cont_level == 0) {
1509 normal:
1510 			// XXX: Pass real fd, then who frees bb?
1511 			buffer_init(bb, -1, NULL, b->fbuf, b->flen);
1512 			ms->offset = offset;
1513 			ms->eoffset = 0;
1514 		} else {
1515 			ms->offset = ms->eoffset + offset;
1516 		}
1517 	}
1518 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1519 		fprintf(stderr, "bb=[%p,%" SIZE_T_FORMAT "u,%"
1520 		    SIZE_T_FORMAT "u], %d [b=%p,%"
1521 		    SIZE_T_FORMAT "u,%" SIZE_T_FORMAT "u], [o=%#x, c=%d]\n",
1522 		    bb->fbuf, bb->flen, bb->elen, ms->offset, b->fbuf,
1523 		    b->flen, b->elen, offset, cont_level);
1524 	}
1525 	return 0;
1526 }
1527 
1528 private int
1529 save_cont(struct magic_set *ms, struct cont *c)
1530 {
1531 	size_t len;
1532 	*c = ms->c;
1533 	len = c->len * sizeof(*c->li);
1534 	ms->c.li = CAST(struct level_info *, malloc(len));
1535 	if (ms->c.li == NULL) {
1536 		ms->c = *c;
1537 		return -1;
1538 	}
1539 	memcpy(ms->c.li, c->li, len);
1540 	return 0;
1541 }
1542 
1543 private void
1544 restore_cont(struct magic_set *ms, struct cont *c)
1545 {
1546 	free(ms->c.li);
1547 	ms->c = *c;
1548 }
1549 
1550 private int
1551 mget(struct magic_set *ms, struct magic *m, const struct buffer *b,
1552     const unsigned char *s, size_t nbytes, size_t o, unsigned int cont_level,
1553     int mode, int text, int flip, uint16_t *indir_count, uint16_t *name_count,
1554     int *printed_something, int *need_separator, int *returnval,
1555     int *found_match)
1556 {
1557 	uint32_t eoffset, offset = ms->offset;
1558 	struct buffer bb;
1559 	intmax_t lhs;
1560 	file_pushbuf_t *pb;
1561 	int rv, oneed_separator, in_type, nfound_match;
1562 	char *rbuf;
1563 	union VALUETYPE *p = &ms->ms_value;
1564 	struct mlist ml;
1565 	struct cont c;
1566 
1567 	if (*indir_count >= ms->indir_max) {
1568 		file_error(ms, 0, "indirect count (%hu) exceeded",
1569 		    *indir_count);
1570 		return -1;
1571 	}
1572 
1573 	if (*name_count >= ms->name_max) {
1574 		file_error(ms, 0, "name use count (%hu) exceeded",
1575 		    *name_count);
1576 		return -1;
1577 	}
1578 
1579 
1580 
1581 	if (mcopy(ms, p, m->type, m->flag & INDIR, s,
1582 	    CAST(uint32_t, offset + o), CAST(uint32_t, nbytes), m) == -1)
1583 		return -1;
1584 
1585 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1586 		fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1587 		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1588 		    "u, il=%hu, nc=%hu)\n",
1589 		    m->type, m->flag, offset, o, nbytes,
1590 		    *indir_count, *name_count);
1591 		mdebug(offset, RCAST(char *, RCAST(void *, p)),
1592 		    sizeof(union VALUETYPE));
1593 #ifndef COMPILE_ONLY
1594 		file_mdump(m);
1595 #endif
1596 	}
1597 
1598 	if (m->flag & INDIR) {
1599 		intmax_t off = m->in_offset;
1600 		const int sgn = m->in_op & FILE_OPSIGNED;
1601 		if (m->in_op & FILE_OPINDIRECT) {
1602 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1603 			    RCAST(const void *, s + offset + off));
1604 			int op;
1605 			switch (op = cvt_flip(m->in_type, flip)) {
1606 			case FILE_BYTE:
1607 				if (OFFSET_OOB(nbytes, offset + off, 1))
1608 					return 0;
1609 				off = SEXT(sgn,8,q->b);
1610 				break;
1611 			case FILE_SHORT:
1612 				if (OFFSET_OOB(nbytes, offset + off, 2))
1613 					return 0;
1614 				off = SEXT(sgn,16,q->h);
1615 				break;
1616 			case FILE_BESHORT:
1617 				if (OFFSET_OOB(nbytes, offset + off, 2))
1618 					return 0;
1619 				off = SEXT(sgn,16,BE16(q));
1620 				break;
1621 			case FILE_LESHORT:
1622 				if (OFFSET_OOB(nbytes, offset + off, 2))
1623 					return 0;
1624 				off = SEXT(sgn,16,LE16(q));
1625 				break;
1626 			case FILE_LONG:
1627 				if (OFFSET_OOB(nbytes, offset + off, 4))
1628 					return 0;
1629 				off = SEXT(sgn,32,q->l);
1630 				break;
1631 			case FILE_BELONG:
1632 			case FILE_BEID3:
1633 				if (OFFSET_OOB(nbytes, offset + off, 4))
1634 					return 0;
1635 				off = SEXT(sgn,32,BE32(q));
1636 				break;
1637 			case FILE_LEID3:
1638 			case FILE_LELONG:
1639 				if (OFFSET_OOB(nbytes, offset + off, 4))
1640 					return 0;
1641 				off = SEXT(sgn,32,LE32(q));
1642 				break;
1643 			case FILE_MELONG:
1644 				if (OFFSET_OOB(nbytes, offset + off, 4))
1645 					return 0;
1646 				off = SEXT(sgn,32,ME32(q));
1647 				break;
1648 			case FILE_BEQUAD:
1649 				if (OFFSET_OOB(nbytes, offset + off, 8))
1650 					return 0;
1651 				off = SEXT(sgn,64,BE64(q));
1652 				break;
1653 			case FILE_LEQUAD:
1654 				if (OFFSET_OOB(nbytes, offset + off, 8))
1655 					return 0;
1656 				off = SEXT(sgn,64,LE64(q));
1657 				break;
1658 			default:
1659 				if ((ms->flags & MAGIC_DEBUG) != 0)
1660 					fprintf(stderr, "bad op=%d\n", op);
1661 				return 0;
1662 			}
1663 			if ((ms->flags & MAGIC_DEBUG) != 0)
1664 				fprintf(stderr, "indirect offs=%jd\n", off);
1665 		}
1666 		switch (in_type = cvt_flip(m->in_type, flip)) {
1667 		case FILE_BYTE:
1668 			if (OFFSET_OOB(nbytes, offset, 1))
1669 				return 0;
1670 			offset = do_ops(m, SEXT(sgn,8,p->b), off);
1671 			break;
1672 		case FILE_BESHORT:
1673 			if (OFFSET_OOB(nbytes, offset, 2))
1674 				return 0;
1675 			offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1676 			break;
1677 		case FILE_LESHORT:
1678 			if (OFFSET_OOB(nbytes, offset, 2))
1679 				return 0;
1680 			offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1681 			break;
1682 		case FILE_SHORT:
1683 			if (OFFSET_OOB(nbytes, offset, 2))
1684 				return 0;
1685 			offset = do_ops(m, SEXT(sgn,16,p->h), off);
1686 			break;
1687 		case FILE_BELONG:
1688 		case FILE_BEID3:
1689 			if (OFFSET_OOB(nbytes, offset, 4))
1690 				return 0;
1691 			lhs = BE32(p);
1692 			if (in_type == FILE_BEID3)
1693 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1694 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1695 			break;
1696 		case FILE_LELONG:
1697 		case FILE_LEID3:
1698 			if (OFFSET_OOB(nbytes, offset, 4))
1699 				return 0;
1700 			lhs = LE32(p);
1701 			if (in_type == FILE_LEID3)
1702 				lhs = cvt_id3(ms, CAST(uint32_t, lhs));
1703 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1704 			break;
1705 		case FILE_MELONG:
1706 			if (OFFSET_OOB(nbytes, offset, 4))
1707 				return 0;
1708 			offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1709 			break;
1710 		case FILE_LONG:
1711 			if (OFFSET_OOB(nbytes, offset, 4))
1712 				return 0;
1713 			offset = do_ops(m, SEXT(sgn,32,p->l), off);
1714 			break;
1715 		case FILE_LEQUAD:
1716 			if (OFFSET_OOB(nbytes, offset, 8))
1717 				return 0;
1718 			offset = do_ops(m, SEXT(sgn,64,LE64(p)), off);
1719 			break;
1720 		case FILE_BEQUAD:
1721 			if (OFFSET_OOB(nbytes, offset, 8))
1722 				return 0;
1723 			offset = do_ops(m, SEXT(sgn,64,BE64(p)), off);
1724 			break;
1725 		default:
1726 			if ((ms->flags & MAGIC_DEBUG) != 0)
1727 				fprintf(stderr, "bad in_type=%d\n", in_type);
1728 			return 0;
1729 		}
1730 
1731 		if (m->flag & INDIROFFADD) {
1732 			if (cont_level == 0) {
1733 				if ((ms->flags & MAGIC_DEBUG) != 0)
1734 					fprintf(stderr,
1735 					    "indirect *zero* cont_level\n");
1736 				return 0;
1737 			}
1738 			offset += ms->c.li[cont_level - 1].off;
1739 			if (offset == 0) {
1740 				if ((ms->flags & MAGIC_DEBUG) != 0)
1741 					fprintf(stderr,
1742 					    "indirect *zero* offset\n");
1743 				return 0;
1744 			}
1745 			if ((ms->flags & MAGIC_DEBUG) != 0)
1746 				fprintf(stderr, "indirect +offs=%u\n", offset);
1747 		}
1748 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1749 			return -1;
1750 		ms->offset = offset;
1751 
1752 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1753 			mdebug(offset, RCAST(char *, RCAST(void *, p)),
1754 			    sizeof(union VALUETYPE));
1755 #ifndef COMPILE_ONLY
1756 			file_mdump(m);
1757 #endif
1758 		}
1759 	}
1760 
1761 	/* Verify we have enough data to match magic type */
1762 	switch (m->type) {
1763 	case FILE_BYTE:
1764 		if (OFFSET_OOB(nbytes, offset, 1))
1765 			return 0;
1766 		break;
1767 
1768 	case FILE_SHORT:
1769 	case FILE_BESHORT:
1770 	case FILE_LESHORT:
1771 		if (OFFSET_OOB(nbytes, offset, 2))
1772 			return 0;
1773 		break;
1774 
1775 	case FILE_LONG:
1776 	case FILE_BELONG:
1777 	case FILE_LELONG:
1778 	case FILE_MELONG:
1779 	case FILE_DATE:
1780 	case FILE_BEDATE:
1781 	case FILE_LEDATE:
1782 	case FILE_MEDATE:
1783 	case FILE_LDATE:
1784 	case FILE_BELDATE:
1785 	case FILE_LELDATE:
1786 	case FILE_MELDATE:
1787 	case FILE_FLOAT:
1788 	case FILE_BEFLOAT:
1789 	case FILE_LEFLOAT:
1790 		if (OFFSET_OOB(nbytes, offset, 4))
1791 			return 0;
1792 		break;
1793 
1794 	case FILE_DOUBLE:
1795 	case FILE_BEDOUBLE:
1796 	case FILE_LEDOUBLE:
1797 		if (OFFSET_OOB(nbytes, offset, 8))
1798 			return 0;
1799 		break;
1800 
1801 	case FILE_GUID:
1802 		if (OFFSET_OOB(nbytes, offset, 16))
1803 			return 0;
1804 		break;
1805 
1806 	case FILE_STRING:
1807 	case FILE_PSTRING:
1808 	case FILE_SEARCH:
1809 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1810 			return 0;
1811 		break;
1812 
1813 	case FILE_REGEX:
1814 		if (nbytes < offset)
1815 			return 0;
1816 		break;
1817 
1818 	case FILE_INDIRECT:
1819 		if (m->str_flags & INDIRECT_RELATIVE)
1820 			offset += CAST(uint32_t, o);
1821 		if (offset == 0)
1822 			return 0;
1823 
1824 		if (nbytes < offset)
1825 			return 0;
1826 
1827 		if ((pb = file_push_buffer(ms)) == NULL)
1828 			return -1;
1829 
1830 		(*indir_count)++;
1831 		bb = *b;
1832 		bb.fbuf = s + offset;
1833 		bb.flen = nbytes - offset;
1834 		rv = file_softmagic(ms, &bb,
1835 		    indir_count, name_count, BINTEST, text);
1836 
1837 		if ((ms->flags & MAGIC_DEBUG) != 0)
1838 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1839 
1840 		rbuf = file_pop_buffer(ms, pb);
1841 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1842 			return -1;
1843 
1844 		if (rv == 1) {
1845 			if ((ms->flags & MAGIC_NODESC) == 0 &&
1846 			    file_printf(ms, F(ms, m->desc, "%u"), offset) == -1)
1847 			{
1848 				free(rbuf);
1849 				return -1;
1850 			}
1851 			if (file_printf(ms, "%s", rbuf) == -1) {
1852 				free(rbuf);
1853 				return -1;
1854 			}
1855 		}
1856 		free(rbuf);
1857 		return rv;
1858 
1859 	case FILE_USE:
1860 		if (nbytes < offset)
1861 			return 0;
1862 		rbuf = m->value.s;
1863 		if (*rbuf == '^') {
1864 			rbuf++;
1865 			flip = !flip;
1866 		}
1867 		if (file_magicfind(ms, rbuf, &ml) == -1) {
1868 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1869 			return -1;
1870 		}
1871 		if (save_cont(ms, &c) == -1) {
1872 			file_error(ms, errno, "can't allocate continuation");
1873 			return -1;
1874 		}
1875 
1876 		oneed_separator = *need_separator;
1877 		if (m->flag & NOSPACE)
1878 			*need_separator = 0;
1879 
1880 		nfound_match = 0;
1881 		(*name_count)++;
1882 		eoffset = ms->eoffset;
1883 		rv = match(ms, ml.magic, ml.nmagic, b, offset + o,
1884 		    mode, text, flip, indir_count, name_count,
1885 		    printed_something, need_separator, returnval,
1886 		    &nfound_match);
1887 		ms->ms_value.q = nfound_match;
1888 		(*name_count)--;
1889 		*found_match |= nfound_match;
1890 
1891 		restore_cont(ms, &c);
1892 
1893 		if (rv != 1)
1894 		    *need_separator = oneed_separator;
1895 		ms->offset = offset;
1896 		ms->eoffset = eoffset;
1897 		return rv;
1898 
1899 	case FILE_NAME:
1900 		if (ms->flags & MAGIC_NODESC)
1901 			return 1;
1902 		if (file_printf(ms, "%s", m->desc) == -1)
1903 			return -1;
1904 		return 1;
1905 	case FILE_DER:
1906 	case FILE_DEFAULT:	/* nothing to check */
1907 	case FILE_CLEAR:
1908 	default:
1909 		break;
1910 	}
1911 	if (!mconvert(ms, m, flip))
1912 		return 0;
1913 	return 1;
1914 }
1915 
1916 private uint64_t
1917 file_strncmp(const char *s1, const char *s2, size_t len, size_t maxlen,
1918     uint32_t flags)
1919 {
1920 	/*
1921 	 * Convert the source args to unsigned here so that (1) the
1922 	 * compare will be unsigned as it is in strncmp() and (2) so
1923 	 * the ctype functions will work correctly without extra
1924 	 * casting.
1925 	 */
1926 	const unsigned char *a = RCAST(const unsigned char *, s1);
1927 	const unsigned char *b = RCAST(const unsigned char *, s2);
1928 	uint32_t ws = flags & (STRING_COMPACT_WHITESPACE |
1929 	    STRING_COMPACT_OPTIONAL_WHITESPACE);
1930 	const unsigned char *eb = b + (ws ? maxlen : len);
1931 	uint64_t v;
1932 
1933 	/*
1934 	 * What we want here is v = strncmp(s1, s2, len),
1935 	 * but ignoring any nulls.
1936 	 */
1937 	v = 0;
1938 	if (0L == flags) { /* normal string: do it fast */
1939 		while (len-- > 0)
1940 			if ((v = *b++ - *a++) != '\0')
1941 				break;
1942 	}
1943 	else { /* combine the others */
1944 		while (len-- > 0) {
1945 			if (b >= eb) {
1946 				v = 1;
1947 				break;
1948 			}
1949 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1950 			    islower(*a)) {
1951 				if ((v = tolower(*b++) - *a++) != '\0')
1952 					break;
1953 			}
1954 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1955 			    isupper(*a)) {
1956 				if ((v = toupper(*b++) - *a++) != '\0')
1957 					break;
1958 			}
1959 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1960 			    isspace(*a)) {
1961 				a++;
1962 				if (isspace(*b++)) {
1963 					if (!isspace(*a))
1964 						while (b < eb && isspace(*b))
1965 							b++;
1966 				}
1967 				else {
1968 					v = 1;
1969 					break;
1970 				}
1971 			}
1972 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1973 			    isspace(*a)) {
1974 				a++;
1975 				while (b < eb && isspace(*b))
1976 					b++;
1977 			}
1978 			else {
1979 				if ((v = *b++ - *a++) != '\0')
1980 					break;
1981 			}
1982 		}
1983 	}
1984 	return v;
1985 }
1986 
1987 private uint64_t
1988 file_strncmp16(const char *a, const char *b, size_t len, size_t maxlen,
1989     uint32_t flags)
1990 {
1991 	/*
1992 	 * XXX - The 16-bit string compare probably needs to be done
1993 	 * differently, especially if the flags are to be supported.
1994 	 * At the moment, I am unsure.
1995 	 */
1996 	flags = 0;
1997 	return file_strncmp(a, b, len, maxlen, flags);
1998 }
1999 
2000 private int
2001 magiccheck(struct magic_set *ms, struct magic *m)
2002 {
2003 	uint64_t l = m->value.q;
2004 	uint64_t v;
2005 	float fl, fv;
2006 	double dl, dv;
2007 	int matched;
2008 	union VALUETYPE *p = &ms->ms_value;
2009 
2010 	switch (m->type) {
2011 	case FILE_BYTE:
2012 		v = p->b;
2013 		break;
2014 
2015 	case FILE_SHORT:
2016 	case FILE_BESHORT:
2017 	case FILE_LESHORT:
2018 		v = p->h;
2019 		break;
2020 
2021 	case FILE_LONG:
2022 	case FILE_BELONG:
2023 	case FILE_LELONG:
2024 	case FILE_MELONG:
2025 	case FILE_DATE:
2026 	case FILE_BEDATE:
2027 	case FILE_LEDATE:
2028 	case FILE_MEDATE:
2029 	case FILE_LDATE:
2030 	case FILE_BELDATE:
2031 	case FILE_LELDATE:
2032 	case FILE_MELDATE:
2033 		v = p->l;
2034 		break;
2035 
2036 	case FILE_QUAD:
2037 	case FILE_LEQUAD:
2038 	case FILE_BEQUAD:
2039 	case FILE_QDATE:
2040 	case FILE_BEQDATE:
2041 	case FILE_LEQDATE:
2042 	case FILE_QLDATE:
2043 	case FILE_BEQLDATE:
2044 	case FILE_LEQLDATE:
2045 	case FILE_QWDATE:
2046 	case FILE_BEQWDATE:
2047 	case FILE_LEQWDATE:
2048 	case FILE_OFFSET:
2049 		v = p->q;
2050 		break;
2051 
2052 	case FILE_FLOAT:
2053 	case FILE_BEFLOAT:
2054 	case FILE_LEFLOAT:
2055 		fl = m->value.f;
2056 		fv = p->f;
2057 		switch (m->reln) {
2058 		case 'x':
2059 			matched = 1;
2060 			break;
2061 
2062 		case '!':
2063 			matched = fv != fl;
2064 			break;
2065 
2066 		case '=':
2067 			matched = fv == fl;
2068 			break;
2069 
2070 		case '>':
2071 			matched = fv > fl;
2072 			break;
2073 
2074 		case '<':
2075 			matched = fv < fl;
2076 			break;
2077 
2078 		default:
2079 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
2080 			    m->reln);
2081 			return -1;
2082 		}
2083 		return matched;
2084 
2085 	case FILE_DOUBLE:
2086 	case FILE_BEDOUBLE:
2087 	case FILE_LEDOUBLE:
2088 		dl = m->value.d;
2089 		dv = p->d;
2090 		switch (m->reln) {
2091 		case 'x':
2092 			matched = 1;
2093 			break;
2094 
2095 		case '!':
2096 			matched = dv != dl;
2097 			break;
2098 
2099 		case '=':
2100 			matched = dv == dl;
2101 			break;
2102 
2103 		case '>':
2104 			matched = dv > dl;
2105 			break;
2106 
2107 		case '<':
2108 			matched = dv < dl;
2109 			break;
2110 
2111 		default:
2112 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
2113 			return -1;
2114 		}
2115 		return matched;
2116 
2117 	case FILE_DEFAULT:
2118 	case FILE_CLEAR:
2119 		l = 0;
2120 		v = 0;
2121 		break;
2122 
2123 	case FILE_STRING:
2124 	case FILE_PSTRING:
2125 		l = 0;
2126 		v = file_strncmp(m->value.s, p->s, CAST(size_t, m->vallen),
2127 		    sizeof(p->s), m->str_flags);
2128 		break;
2129 
2130 	case FILE_BESTRING16:
2131 	case FILE_LESTRING16:
2132 		l = 0;
2133 		v = file_strncmp16(m->value.s, p->s, CAST(size_t, m->vallen),
2134 		    sizeof(p->s), m->str_flags);
2135 		break;
2136 
2137 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
2138 		size_t slen;
2139 		size_t idx;
2140 
2141 		if (ms->search.s == NULL)
2142 			return 0;
2143 
2144 		slen = MIN(m->vallen, sizeof(m->value.s));
2145 		l = 0;
2146 		v = 0;
2147 #ifdef HAVE_MEMMEM
2148 		if (slen > 0 && m->str_flags == 0) {
2149 			const char *found;
2150 			idx = m->str_range + slen;
2151 			if (m->str_range == 0 || ms->search.s_len < idx)
2152 				idx = ms->search.s_len;
2153 			found = CAST(const char *, memmem(ms->search.s, idx,
2154 			    m->value.s, slen));
2155 			if (!found)
2156 				return 0;
2157 			idx = found - ms->search.s;
2158 			ms->search.offset += idx;
2159 			ms->search.rm_len = ms->search.s_len - idx;
2160 			break;
2161 		}
2162 #endif
2163 
2164 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
2165 			if (slen + idx > ms->search.s_len)
2166 				return 0;
2167 
2168 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
2169 			    ms->search.s_len - idx, m->str_flags);
2170 			if (v == 0) {	/* found match */
2171 				ms->search.offset += idx;
2172 				ms->search.rm_len = ms->search.s_len - idx;
2173 				break;
2174 			}
2175 		}
2176 		break;
2177 	}
2178 	case FILE_REGEX: {
2179 		int rc;
2180 		file_regex_t rx;
2181 		const char *search;
2182 
2183 		if (ms->search.s == NULL)
2184 			return 0;
2185 
2186 		l = 0;
2187 		rc = file_regcomp(&rx, m->value.s,
2188 		    REG_EXTENDED|REG_NEWLINE|
2189 		    ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0));
2190 		if (rc) {
2191 			file_regerror(&rx, rc, ms);
2192 			v = CAST(uint64_t, -1);
2193 		} else {
2194 			regmatch_t pmatch;
2195 			size_t slen = ms->search.s_len;
2196 			char *copy;
2197 			if (slen != 0) {
2198 			    copy = CAST(char *, malloc(slen));
2199 			    if (copy == NULL)  {
2200 				file_regfree(&rx);
2201 				file_error(ms, errno,
2202 				    "can't allocate %" SIZE_T_FORMAT "u bytes",
2203 				    slen);
2204 				return -1;
2205 			    }
2206 			    memcpy(copy, ms->search.s, slen);
2207 			    copy[--slen] = '\0';
2208 			    search = copy;
2209 			} else {
2210 			    search = CCAST(char *, "");
2211 			    copy = NULL;
2212 			}
2213 			rc = file_regexec(&rx, RCAST(const char *, search),
2214 			    1, &pmatch, 0);
2215 			free(copy);
2216 			switch (rc) {
2217 			case 0:
2218 				ms->search.s += CAST(int, pmatch.rm_so);
2219 				ms->search.offset += CAST(size_t, pmatch.rm_so);
2220 				ms->search.rm_len = CAST(size_t,
2221 				    pmatch.rm_eo - pmatch.rm_so);
2222 				v = 0;
2223 				break;
2224 
2225 			case REG_NOMATCH:
2226 				v = 1;
2227 				break;
2228 
2229 			default:
2230 				file_regerror(&rx, rc, ms);
2231 				v = CAST(uint64_t, -1);
2232 				break;
2233 			}
2234 		}
2235 		file_regfree(&rx);
2236 		if (v == CAST(uint64_t, -1))
2237 			return -1;
2238 		break;
2239 	}
2240 	case FILE_USE:
2241 		return ms->ms_value.q != 0;
2242 	case FILE_NAME:
2243 	case FILE_INDIRECT:
2244 		return 1;
2245 	case FILE_DER:
2246 		matched = der_cmp(ms, m);
2247 		if (matched == -1) {
2248 			if ((ms->flags & MAGIC_DEBUG) != 0) {
2249 				(void) fprintf(stderr,
2250 				    "EOF comparing DER entries");
2251 			}
2252 			return 0;
2253 		}
2254 		return matched;
2255 	case FILE_GUID:
2256 		l = 0;
2257 		v = memcmp(m->value.guid, p->guid, sizeof(p->guid));
2258 		break;
2259 	default:
2260 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
2261 		return -1;
2262 	}
2263 
2264 	v = file_signextend(ms, m, v);
2265 
2266 	switch (m->reln) {
2267 	case 'x':
2268 		if ((ms->flags & MAGIC_DEBUG) != 0)
2269 			(void) fprintf(stderr, "%" INT64_T_FORMAT
2270 			    "u == *any* = 1\n", CAST(unsigned long long, v));
2271 		matched = 1;
2272 		break;
2273 
2274 	case '!':
2275 		matched = v != l;
2276 		if ((ms->flags & MAGIC_DEBUG) != 0)
2277 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
2278 			    INT64_T_FORMAT "u = %d\n",
2279 			    CAST(unsigned long long, v),
2280 			    CAST(unsigned long long, l), matched);
2281 		break;
2282 
2283 	case '=':
2284 		matched = v == l;
2285 		if ((ms->flags & MAGIC_DEBUG) != 0)
2286 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
2287 			    INT64_T_FORMAT "u = %d\n",
2288 			    CAST(unsigned long long, v),
2289 			    CAST(unsigned long long, l), matched);
2290 		break;
2291 
2292 	case '>':
2293 		if (m->flag & UNSIGNED) {
2294 			matched = v > l;
2295 			if ((ms->flags & MAGIC_DEBUG) != 0)
2296 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2297 				    "u > %" INT64_T_FORMAT "u = %d\n",
2298 				    CAST(unsigned long long, v),
2299 				    CAST(unsigned long long, l), matched);
2300 		}
2301 		else {
2302 			matched = CAST(int64_t, v) > CAST(int64_t, l);
2303 			if ((ms->flags & MAGIC_DEBUG) != 0)
2304 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2305 				    "d > %" INT64_T_FORMAT "d = %d\n",
2306 				    CAST(long long, v),
2307 				    CAST(long long, l), matched);
2308 		}
2309 		break;
2310 
2311 	case '<':
2312 		if (m->flag & UNSIGNED) {
2313 			matched = v < l;
2314 			if ((ms->flags & MAGIC_DEBUG) != 0)
2315 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2316 				    "u < %" INT64_T_FORMAT "u = %d\n",
2317 				    CAST(unsigned long long, v),
2318 				    CAST(unsigned long long, l), matched);
2319 		}
2320 		else {
2321 			matched = CAST(int64_t, v) < CAST(int64_t, l);
2322 			if ((ms->flags & MAGIC_DEBUG) != 0)
2323 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2324 				    "d < %" INT64_T_FORMAT "d = %d\n",
2325 				     CAST(long long, v),
2326 				     CAST(long long, l), matched);
2327 		}
2328 		break;
2329 
2330 	case '&':
2331 		matched = (v & l) == l;
2332 		if ((ms->flags & MAGIC_DEBUG) != 0)
2333 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2334 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2335 			    "x) = %d\n", CAST(unsigned long long, v),
2336 			    CAST(unsigned long long, l),
2337 			    CAST(unsigned long long, l),
2338 			    matched);
2339 		break;
2340 
2341 	case '^':
2342 		matched = (v & l) != l;
2343 		if ((ms->flags & MAGIC_DEBUG) != 0)
2344 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2345 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2346 			    "x) = %d\n", CAST(unsigned long long, v),
2347 			    CAST(unsigned long long, l),
2348 			    CAST(unsigned long long, l), matched);
2349 		break;
2350 
2351 	default:
2352 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2353 		    m->reln);
2354 		return -1;
2355 	}
2356 
2357 	return matched;
2358 }
2359 
2360 private int
2361 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2362 {
2363 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2364 		if (print_sep(ms, firstline) == -1)
2365 			return -1;
2366 		if (file_printf(ms, "%.8s", m->apple) == -1)
2367 			return -1;
2368 		return 1;
2369 	}
2370 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2371 		if (print_sep(ms, firstline) == -1)
2372 			return -1;
2373 		if (file_printf(ms, "%s", m->ext) == -1)
2374 			return -1;
2375 		return 1;
2376 	}
2377 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2378 		char buf[1024];
2379 		const char *p;
2380 		if (print_sep(ms, firstline) == -1)
2381 			return -1;
2382 		if (varexpand(ms, buf, sizeof(buf), m->mimetype) == -1)
2383 			p = m->mimetype;
2384 		else
2385 			p = buf;
2386 		if (file_printf(ms, "%s", p) == -1)
2387 			return -1;
2388 		return 1;
2389 	}
2390 	return 0;
2391 }
2392 
2393 private int
2394 print_sep(struct magic_set *ms, int firstline)
2395 {
2396 	if (firstline)
2397 		return 0;
2398 	/*
2399 	 * we found another match
2400 	 * put a newline and '-' to do some simple formatting
2401 	 */
2402 	return file_separator(ms);
2403 }
2404