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