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