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