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