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