xref: /PHP-7.2/ext/fileinfo/libmagic/softmagic.c (revision 9d77bf09)
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.248 2017/04/21 16:54:57 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 #ifndef PREG_OFFSET_CAPTURE
47 # define PREG_OFFSET_CAPTURE                 (1<<8)
48 #endif
49 
50 private int match(struct magic_set *, struct magic *, uint32_t,
51     const unsigned char *, size_t, size_t, int, int, int, uint16_t *,
52     uint16_t *, int *, int *, int *);
53 private int mget(struct magic_set *, const unsigned char *,
54     struct magic *, size_t, size_t, unsigned int, int, int, int, uint16_t *,
55     uint16_t *, int *, int *, int *);
56 private int magiccheck(struct magic_set *, struct magic *);
57 private int32_t mprint(struct magic_set *, struct magic *);
58 private int moffset(struct magic_set *, struct magic *, size_t, 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) < (uint32_t)(o) || (i) > ((n) - (o)))
71 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
72     ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
73     ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
74     ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
75 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
76     ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
77     ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
78     ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
79 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
80      ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
81 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
82      ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
83 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
84      ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
85 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
86 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
87 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
88 
89 /*
90  * softmagic - lookup one file in parsed, in-memory copy of database
91  * Passed the name and FILE * of one file to be typed.
92  */
93 /*ARGSUSED1*/		/* nbytes passed for regularity, maybe need later */
94 protected int
file_softmagic(struct magic_set * ms,const unsigned char * buf,size_t nbytes,uint16_t * indir_count,uint16_t * name_count,int mode,int text)95 file_softmagic(struct magic_set *ms, const unsigned char *buf, size_t nbytes,
96     uint16_t *indir_count, uint16_t *name_count, int mode, int text)
97 {
98 	struct mlist *ml;
99 	int rv, printed_something = 0, need_separator = 0;
100 	uint16_t nc, ic;
101 
102 	if (name_count == NULL) {
103 		nc = 0;
104 		name_count = &nc;
105 	}
106 	if (indir_count == NULL) {
107 		ic = 0;
108 		indir_count = &ic;
109 	}
110 
111 	for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next)
112 		if ((rv = match(ms, ml->magic, ml->nmagic, buf, nbytes, 0, mode,
113 		    text, 0, indir_count, name_count,
114 		    &printed_something, &need_separator, NULL)) != 0)
115 			return rv;
116 
117 	return 0;
118 }
119 
120 
121 #if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK)
122 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
123 
124 private const char * __attribute__((__format_arg__(3)))
file_fmtcheck(struct magic_set * ms,const struct magic * m,const char * def,const char * file,size_t line)125 file_fmtcheck(struct magic_set *ms, const struct magic *m, const char *def,
126 	const char *file, size_t line)
127 {
128 	const char *ptr = fmtcheck(m->desc, def);
129 	if (ptr == def)
130 		file_magerror(ms,
131 		    "%s, %" SIZE_T_FORMAT "u: format `%s' does not match"
132 		    " with `%s'", file, line, m->desc, def);
133 	return ptr;
134 }
135 #elif defined(HAVE_FMTCHECK)
136 #define F(a, b, c) fmtcheck((b)->desc, (c))
137 #else
138 #define F(a, b, c) ((b)->desc)
139 #endif
140 
141 /*
142  * Go through the whole list, stopping if you find a match.  Process all
143  * the continuations of that match before returning.
144  *
145  * We support multi-level continuations:
146  *
147  *	At any time when processing a successful top-level match, there is a
148  *	current continuation level; it represents the level of the last
149  *	successfully matched continuation.
150  *
151  *	Continuations above that level are skipped as, if we see one, it
152  *	means that the continuation that controls them - i.e, the
153  *	lower-level continuation preceding them - failed to match.
154  *
155  *	Continuations below that level are processed as, if we see one,
156  *	it means we've finished processing or skipping higher-level
157  *	continuations under the control of a successful or unsuccessful
158  *	lower-level continuation, and are now seeing the next lower-level
159  *	continuation and should process it.  The current continuation
160  *	level reverts to the level of the one we're seeing.
161  *
162  *	Continuations at the current level are processed as, if we see
163  *	one, there's no lower-level continuation that may have failed.
164  *
165  *	If a continuation matches, we bump the current continuation level
166  *	so that higher-level continuations are processed.
167  */
168 private int
match(struct magic_set * ms,struct magic * magic,uint32_t nmagic,const unsigned char * s,size_t nbytes,size_t offset,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)169 match(struct magic_set *ms, struct magic *magic, uint32_t nmagic,
170     const unsigned char *s, size_t nbytes, size_t offset, int mode, int text,
171     int flip, uint16_t *indir_count, uint16_t *name_count,
172     int *printed_something, int *need_separator, int *returnval)
173 {
174 	uint32_t magindex = 0;
175 	unsigned int cont_level = 0;
176 	int returnvalv = 0, e; /* if a match is found it is set to 1*/
177 	int firstline = 1; /* a flag to print X\n  X\n- X */
178 	int print = (ms->flags & MAGIC_NODESC) == 0;
179 
180 	if (returnval == NULL)
181 		returnval = &returnvalv;
182 
183 	if (file_check_mem(ms, cont_level) == -1)
184 		return -1;
185 
186 	for (magindex = 0; magindex < nmagic; magindex++) {
187 		int flush = 0;
188 		struct magic *m = &magic[magindex];
189 
190 		if (m->type != FILE_NAME)
191 		if ((IS_LIBMAGIC_STRING(m->type) &&
192 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
193 		     ((text && (m->str_flags & FLT) == STRING_BINTEST) ||
194 		      (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) ||
195 		    (m->flag & mode) != mode) {
196 flush:
197 			/* Skip sub-tests */
198 			while (magindex < nmagic - 1 &&
199 			    magic[magindex + 1].cont_level != 0)
200 				magindex++;
201 			cont_level = 0;
202 			continue; /* Skip to next top-level test*/
203 		}
204 
205 		ms->offset = m->offset;
206 		ms->line = m->lineno;
207 
208 		/* if main entry matches, print it... */
209 		switch (mget(ms, s, m, nbytes, offset, cont_level, mode, text,
210 		    flip, indir_count, name_count,
211 		    printed_something, need_separator, returnval)) {
212 		case -1:
213 			return -1;
214 		case 0:
215 			flush = m->reln != '!';
216 			break;
217 		default:
218 			if (m->type == FILE_INDIRECT)
219 				*returnval = 1;
220 
221 			switch (magiccheck(ms, m)) {
222 			case -1:
223 				return -1;
224 			case 0:
225 				flush++;
226 				break;
227 			default:
228 				flush = 0;
229 				break;
230 			}
231 			break;
232 		}
233 		if (flush) {
234 			/*
235 			 * main entry didn't match,
236 			 * flush its continuations
237 			 */
238 			goto flush;
239 		}
240 
241 		if ((e = handle_annotation(ms, m, firstline)) != 0) {
242 			*need_separator = 1;
243 			*printed_something = 1;
244 			*returnval = 1;
245 			return e;
246 		}
247 
248 		/*
249 		 * If we are going to print something, we'll need to print
250 		 * a blank before we print something else.
251 		 */
252 		if (*m->desc) {
253 			*need_separator = 1;
254 			*printed_something = 1;
255 			if (print_sep(ms, firstline) == -1)
256 				return -1;
257 		}
258 
259 
260 		if (print && mprint(ms, m) == -1)
261 			return -1;
262 
263 		switch (moffset(ms, m, nbytes, &ms->c.li[cont_level].off)) {
264 		case -1:
265 		case 0:
266 			goto flush;
267 		default:
268 			break;
269 		}
270 
271 		/* and any continuations that match */
272 		if (file_check_mem(ms, ++cont_level) == -1)
273 			return -1;
274 
275 		while (magindex + 1 < nmagic &&
276 		    magic[magindex + 1].cont_level != 0) {
277 			m = &magic[++magindex];
278 			ms->line = m->lineno; /* for messages */
279 
280 			if (cont_level < m->cont_level)
281 				continue;
282 			if (cont_level > m->cont_level) {
283 				/*
284 				 * We're at the end of the level
285 				 * "cont_level" continuations.
286 				 */
287 				cont_level = m->cont_level;
288 			}
289 			ms->offset = m->offset;
290 			if (m->flag & OFFADD) {
291 				ms->offset +=
292 				    ms->c.li[cont_level - 1].off;
293 			}
294 
295 #ifdef ENABLE_CONDITIONALS
296 			if (m->cond == COND_ELSE ||
297 			    m->cond == COND_ELIF) {
298 				if (ms->c.li[cont_level].last_match == 1)
299 					continue;
300 			}
301 #endif
302 			switch (mget(ms, s, m, nbytes, offset, cont_level, mode,
303 			    text, flip, indir_count, name_count,
304 			    printed_something, need_separator, returnval)) {
305 			case -1:
306 				return -1;
307 			case 0:
308 				if (m->reln != '!')
309 					continue;
310 				flush = 1;
311 				break;
312 			default:
313 				if (m->type == FILE_INDIRECT)
314 					*returnval = 1;
315 				flush = 0;
316 				break;
317 			}
318 
319 			switch (flush ? 1 : magiccheck(ms, m)) {
320 			case -1:
321 				return -1;
322 			case 0:
323 #ifdef ENABLE_CONDITIONALS
324 				ms->c.li[cont_level].last_match = 0;
325 #endif
326 				break;
327 			default:
328 #ifdef ENABLE_CONDITIONALS
329 				ms->c.li[cont_level].last_match = 1;
330 #endif
331 				if (m->type == FILE_CLEAR)
332 					ms->c.li[cont_level].got_match = 0;
333 				else if (ms->c.li[cont_level].got_match) {
334 					if (m->type == FILE_DEFAULT)
335 						break;
336 				} else
337 					ms->c.li[cont_level].got_match = 1;
338 
339 				if ((e = handle_annotation(ms, m, firstline)) != 0) {
340 					*need_separator = 1;
341 					*printed_something = 1;
342 					*returnval = 1;
343 					return e;
344 				}
345 				/*
346 				 * If we are going to print something,
347 				 * make sure that we have a separator first.
348 				 */
349 				if (*m->desc) {
350 					if (!*printed_something) {
351 						*printed_something = 1;
352 						if (print_sep(ms, firstline)
353 						    == -1)
354 							return -1;
355 					}
356 				}
357 				/*
358 				 * This continuation matched.  Print
359 				 * its message, with a blank before it
360 				 * if the previous item printed and
361 				 * this item isn't empty.
362 				 */
363 				/* space if previous printed */
364 				if (*need_separator
365 				    && ((m->flag & NOSPACE) == 0)
366 				    && *m->desc) {
367 					if (print &&
368 					    file_printf(ms, " ") == -1)
369 						return -1;
370 					*need_separator = 0;
371 				}
372 				if (print && mprint(ms, m) == -1)
373 					return -1;
374 
375 				switch (moffset(ms, m, nbytes,
376 				    &ms->c.li[cont_level].off)) {
377 				case -1:
378 				case 0:
379 					flush = 1;
380 					cont_level--;
381 					break;
382 				default:
383 					break;
384 				}
385 
386 				if (*m->desc)
387 					*need_separator = 1;
388 
389 				/*
390 				 * If we see any continuations
391 				 * at a higher level,
392 				 * process them.
393 				 */
394 				if (file_check_mem(ms, ++cont_level) == -1)
395 					return -1;
396 				break;
397 			}
398 		}
399 		if (*printed_something) {
400 			firstline = 0;
401 			if (print)
402 				*returnval = 1;
403 		}
404 		if ((ms->flags & MAGIC_CONTINUE) == 0 && *printed_something) {
405 			return *returnval; /* don't keep searching */
406 		}
407 		cont_level = 0;
408 	}
409 	return *returnval;  /* This is hit if -k is set or there is no match */
410 }
411 
412 private int
check_fmt(struct magic_set * ms,struct magic * m)413 check_fmt(struct magic_set *ms, struct magic *m)
414 {
415 	pcre *pce;
416 	int re_options, rv = -1;
417 	pcre_extra *re_extra;
418 	zend_string *pattern;
419 
420 	if (strchr(m->desc, '%') == NULL)
421 		return 0;
422 
423 	(void)setlocale(LC_CTYPE, "C");
424 	pattern = zend_string_init("~%[-0-9\\.]*s~", sizeof("~%[-0-9\\.]*s~") - 1, 0);
425 	if ((pce = pcre_get_compiled_regex(pattern, &re_extra, &re_options)) == NULL) {
426 		rv = -1;
427 	} else {
428 	 	rv = !pcre_exec(pce, re_extra, m->desc, strlen(m->desc), 0, re_options, NULL, 0);
429 	}
430 	zend_string_release(pattern);
431 	(void)setlocale(LC_CTYPE, "");
432 	return rv;
433 }
434 
435 private int32_t
mprint(struct magic_set * ms,struct magic * m)436 mprint(struct magic_set *ms, struct magic *m)
437 {
438 	uint64_t v;
439 	float vf;
440 	double vd;
441 	int64_t t = 0;
442  	char buf[128], tbuf[26], sbuf[512];
443 	union VALUETYPE *p = &ms->ms_value;
444 
445   	switch (m->type) {
446   	case FILE_BYTE:
447 		v = file_signextend(ms, m, (uint64_t)p->b);
448 		switch (check_fmt(ms, m)) {
449 		case -1:
450 			return -1;
451 		case 1:
452 			(void)snprintf(buf, sizeof(buf), "%d",
453 			    (unsigned char)v);
454 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
455 				return -1;
456 			break;
457 		default:
458 			if (file_printf(ms, F(ms, m, "%d"),
459 			    (unsigned char) v) == -1)
460 				return -1;
461 			break;
462 		}
463 		t = ms->offset + sizeof(char);
464 		break;
465 
466   	case FILE_SHORT:
467   	case FILE_BESHORT:
468   	case FILE_LESHORT:
469 		v = file_signextend(ms, m, (uint64_t)p->h);
470 		switch (check_fmt(ms, m)) {
471 		case -1:
472 			return -1;
473 		case 1:
474 			(void)snprintf(buf, sizeof(buf), "%u",
475 			    (unsigned short)v);
476 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
477 				return -1;
478 			break;
479 		default:
480 			if (file_printf(ms, F(ms, m, "%u"),
481 			    (unsigned short) v) == -1)
482 				return -1;
483 			break;
484 		}
485 		t = ms->offset + sizeof(short);
486 		break;
487 
488   	case FILE_LONG:
489   	case FILE_BELONG:
490   	case FILE_LELONG:
491   	case FILE_MELONG:
492 		v = file_signextend(ms, m, (uint64_t)p->l);
493 		switch (check_fmt(ms, m)) {
494 		case -1:
495 			return -1;
496 		case 1:
497 			(void)snprintf(buf, sizeof(buf), "%u", (uint32_t) v);
498 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
499 				return -1;
500 			break;
501 		default:
502 			if (file_printf(ms, F(ms, m, "%u"), (uint32_t) v) == -1)
503 				return -1;
504 			break;
505 		}
506 		t = ms->offset + sizeof(int32_t);
507   		break;
508 
509   	case FILE_QUAD:
510   	case FILE_BEQUAD:
511   	case FILE_LEQUAD:
512 		v = file_signextend(ms, m, p->q);
513 		switch (check_fmt(ms, m)) {
514 		case -1:
515 			return -1;
516 		case 1:
517 			(void)snprintf(buf, sizeof(buf), "%" INT64_T_FORMAT "u",
518 			    (unsigned long long)v);
519 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
520 				return -1;
521 			break;
522 		default:
523 			if (file_printf(ms, F(ms, m, "%" INT64_T_FORMAT "u"),
524 			    (unsigned long long) v) == -1)
525 				return -1;
526 			break;
527 		}
528 		t = ms->offset + sizeof(int64_t);
529   		break;
530 
531   	case FILE_STRING:
532   	case FILE_PSTRING:
533   	case FILE_BESTRING16:
534   	case FILE_LESTRING16:
535 		if (m->reln == '=' || m->reln == '!') {
536 			if (file_printf(ms, F(ms, m, "%s"),
537 			    file_printable(sbuf, sizeof(sbuf), m->value.s))
538 			    == -1)
539 				return -1;
540 			t = ms->offset + m->vallen;
541 		}
542 		else {
543 			char *str = p->s;
544 
545 			/* compute t before we mangle the string? */
546 			t = ms->offset + strlen(str);
547 
548 			if (*m->value.s == '\0')
549 				str[strcspn(str, "\r\n")] = '\0';
550 
551 			if (m->str_flags & STRING_TRIM) {
552 				char *last;
553 				while (isspace((unsigned char)*str))
554 					str++;
555 				last = str;
556 				while (*last)
557 					last++;
558 				--last;
559 				while (isspace((unsigned char)*last))
560 					last--;
561 				*++last = '\0';
562 			}
563 
564 			if (file_printf(ms, F(ms, m, "%s"),
565 			    file_printable(sbuf, sizeof(sbuf), str)) == -1)
566 				return -1;
567 
568 			if (m->type == FILE_PSTRING)
569 				t += file_pstring_length_size(m);
570 		}
571 		break;
572 
573 	case FILE_DATE:
574 	case FILE_BEDATE:
575 	case FILE_LEDATE:
576 	case FILE_MEDATE:
577 		if (file_printf(ms, F(ms, m, "%s"),
578 		    file_fmttime(p->l, 0, tbuf)) == -1)
579 			return -1;
580 		t = ms->offset + sizeof(uint32_t);
581 		break;
582 
583 	case FILE_LDATE:
584 	case FILE_BELDATE:
585 	case FILE_LELDATE:
586 	case FILE_MELDATE:
587 		if (file_printf(ms, F(ms, m, "%s"),
588 		    file_fmttime(p->l, FILE_T_LOCAL, tbuf)) == -1)
589 			return -1;
590 		t = ms->offset + sizeof(uint32_t);
591 		break;
592 
593 	case FILE_QDATE:
594 	case FILE_BEQDATE:
595 	case FILE_LEQDATE:
596 		if (file_printf(ms, F(ms, m, "%s"),
597 		    file_fmttime(p->q, 0, tbuf)) == -1)
598 			return -1;
599 		t = ms->offset + sizeof(uint64_t);
600 		break;
601 
602 	case FILE_QLDATE:
603 	case FILE_BEQLDATE:
604 	case FILE_LEQLDATE:
605 		if (file_printf(ms, F(ms, m, "%s"),
606 		    file_fmttime(p->q, FILE_T_LOCAL, tbuf)) == -1)
607 			return -1;
608 		t = ms->offset + sizeof(uint64_t);
609 		break;
610 
611 	case FILE_QWDATE:
612 	case FILE_BEQWDATE:
613 	case FILE_LEQWDATE:
614 		if (file_printf(ms, F(ms, m, "%s"),
615 		    file_fmttime(p->q, FILE_T_WINDOWS, tbuf)) == -1)
616 			return -1;
617 		t = ms->offset + sizeof(uint64_t);
618 		break;
619 
620 	case FILE_FLOAT:
621 	case FILE_BEFLOAT:
622 	case FILE_LEFLOAT:
623 		vf = p->f;
624 		switch (check_fmt(ms, m)) {
625 		case -1:
626 			return -1;
627 		case 1:
628 			(void)snprintf(buf, sizeof(buf), "%g", vf);
629 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
630 				return -1;
631 			break;
632 		default:
633 			if (file_printf(ms, F(ms, m, "%g"), vf) == -1)
634 				return -1;
635 			break;
636 		}
637 		t = ms->offset + sizeof(float);
638   		break;
639 
640 	case FILE_DOUBLE:
641 	case FILE_BEDOUBLE:
642 	case FILE_LEDOUBLE:
643 		vd = p->d;
644 		switch (check_fmt(ms, m)) {
645 		case -1:
646 			return -1;
647 		case 1:
648 			(void)snprintf(buf, sizeof(buf), "%g", vd);
649 			if (file_printf(ms, F(ms, m, "%s"), buf) == -1)
650 				return -1;
651 			break;
652 		default:
653 			if (file_printf(ms, F(ms, m, "%g"), vd) == -1)
654 				return -1;
655 			break;
656 		}
657 		t = ms->offset + sizeof(double);
658   		break;
659 
660 	case FILE_SEARCH:
661 	case FILE_REGEX: {
662 		char *cp;
663 		int rval;
664 
665 		cp = estrndup((const char *)ms->search.s, ms->search.rm_len);
666 		rval = file_printf(ms, F(ms, m, "%s"),
667 		    file_printable(sbuf, sizeof(sbuf), cp));
668 		efree(cp);
669 
670 		if (rval == -1)
671 			return -1;
672 
673 		if ((m->str_flags & REGEX_OFFSET_START))
674 			t = ms->search.offset;
675 		else
676 			t = ms->search.offset + ms->search.rm_len;
677 		break;
678 	}
679 
680 	case FILE_DEFAULT:
681 	case FILE_CLEAR:
682 	  	if (file_printf(ms, "%s", m->desc) == -1)
683 			return -1;
684 		t = ms->offset;
685 		break;
686 
687 	case FILE_INDIRECT:
688 	case FILE_USE:
689 	case FILE_NAME:
690 		t = ms->offset;
691 		break;
692 	case FILE_DER:
693 		if (file_printf(ms, F(ms, m, "%s"),
694 		    file_printable(sbuf, sizeof(sbuf), ms->ms_value.s)) == -1)
695 			return -1;
696 		t = ms->offset;
697 		break;
698 	default:
699 		file_magerror(ms, "invalid m->type (%d) in mprint()", m->type);
700 		return -1;
701 	}
702 	return (int32_t)t;
703 }
704 
705 private int
moffset(struct magic_set * ms,struct magic * m,size_t nbytes,int32_t * op)706 moffset(struct magic_set *ms, struct magic *m, size_t nbytes, int32_t *op)
707 {
708 	int32_t o;
709 
710   	switch (m->type) {
711   	case FILE_BYTE:
712 		o = CAST(int32_t, (ms->offset + sizeof(char)));
713 		break;
714 
715   	case FILE_SHORT:
716   	case FILE_BESHORT:
717   	case FILE_LESHORT:
718 		o = CAST(int32_t, (ms->offset + sizeof(short)));
719 		break;
720 
721   	case FILE_LONG:
722   	case FILE_BELONG:
723   	case FILE_LELONG:
724   	case FILE_MELONG:
725 		o = CAST(int32_t, (ms->offset + sizeof(int32_t)));
726 		break;
727 
728   	case FILE_QUAD:
729   	case FILE_BEQUAD:
730   	case FILE_LEQUAD:
731 		o = CAST(int32_t, (ms->offset + sizeof(int64_t)));
732 		break;
733 
734   	case FILE_STRING:
735   	case FILE_PSTRING:
736   	case FILE_BESTRING16:
737   	case FILE_LESTRING16:
738 		if (m->reln == '=' || m->reln == '!') {
739 			o = ms->offset + m->vallen;
740 		} else {
741 			union VALUETYPE *p = &ms->ms_value;
742 
743 			if (*m->value.s == '\0')
744 				p->s[strcspn(p->s, "\r\n")] = '\0';
745 			o = CAST(uint32_t, (ms->offset + strlen(p->s)));
746 			if (m->type == FILE_PSTRING)
747 				o += (uint32_t)file_pstring_length_size(m);
748 		}
749 		break;
750 
751 	case FILE_DATE:
752 	case FILE_BEDATE:
753 	case FILE_LEDATE:
754 	case FILE_MEDATE:
755 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
756 		break;
757 
758 	case FILE_LDATE:
759 	case FILE_BELDATE:
760 	case FILE_LELDATE:
761 	case FILE_MELDATE:
762 		o = CAST(int32_t, (ms->offset + sizeof(uint32_t)));
763 		break;
764 
765 	case FILE_QDATE:
766 	case FILE_BEQDATE:
767 	case FILE_LEQDATE:
768 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
769 		break;
770 
771 	case FILE_QLDATE:
772 	case FILE_BEQLDATE:
773 	case FILE_LEQLDATE:
774 		o = CAST(int32_t, (ms->offset + sizeof(uint64_t)));
775 		break;
776 
777   	case FILE_FLOAT:
778   	case FILE_BEFLOAT:
779   	case FILE_LEFLOAT:
780 		o = CAST(int32_t, (ms->offset + sizeof(float)));
781 		break;
782 
783   	case FILE_DOUBLE:
784   	case FILE_BEDOUBLE:
785   	case FILE_LEDOUBLE:
786 		o = CAST(int32_t, (ms->offset + sizeof(double)));
787 		break;
788 
789 	case FILE_REGEX:
790 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
791 			o = CAST(int32_t, ms->search.offset);
792 		else
793 			o = CAST(int32_t,
794 			    (ms->search.offset + ms->search.rm_len));
795 		break;
796 
797 	case FILE_SEARCH:
798 		if ((m->str_flags & REGEX_OFFSET_START) != 0)
799 			o = CAST(int32_t, ms->search.offset);
800 		else
801 			o = CAST(int32_t, (ms->search.offset + m->vallen));
802 		break;
803 
804 	case FILE_CLEAR:
805 	case FILE_DEFAULT:
806 	case FILE_INDIRECT:
807 		o = ms->offset;
808 		break;
809 
810 	case FILE_DER:
811 		{
812 			o = der_offs(ms, m, nbytes);
813 			if (o == -1 || (size_t)o > nbytes) {
814 				if ((ms->flags & MAGIC_DEBUG) != 0) {
815 					(void)fprintf(stderr,
816 					    "Bad DER offset %d nbytes=%zu",
817 					    o, nbytes);
818 				}
819 				*op = 0;
820 				return 0;
821 			}
822 			break;
823 		}
824 
825 	default:
826 		o = 0;
827 		break;
828 	}
829 
830 	if ((size_t)o > nbytes) {
831 #if 0
832 		file_error(ms, 0, "Offset out of range %zu > %zu",
833 		    (size_t)o, nbytes);
834 #endif
835 		return -1;
836 	}
837 	*op = o;
838 	return 1;
839 }
840 
841 private uint32_t
cvt_id3(struct magic_set * ms,uint32_t v)842 cvt_id3(struct magic_set *ms, uint32_t v)
843 {
844 	v = ((((v >>  0) & 0x7f) <<  0) |
845 	     (((v >>  8) & 0x7f) <<  7) |
846 	     (((v >> 16) & 0x7f) << 14) |
847 	     (((v >> 24) & 0x7f) << 21));
848 	if ((ms->flags & MAGIC_DEBUG) != 0)
849 		fprintf(stderr, "id3 offs=%u\n", v);
850 	return v;
851 }
852 
853 private int
cvt_flip(int type,int flip)854 cvt_flip(int type, int flip)
855 {
856 	if (flip == 0)
857 		return type;
858 	switch (type) {
859 	case FILE_BESHORT:
860 		return FILE_LESHORT;
861 	case FILE_BELONG:
862 		return FILE_LELONG;
863 	case FILE_BEDATE:
864 		return FILE_LEDATE;
865 	case FILE_BELDATE:
866 		return FILE_LELDATE;
867 	case FILE_BEQUAD:
868 		return FILE_LEQUAD;
869 	case FILE_BEQDATE:
870 		return FILE_LEQDATE;
871 	case FILE_BEQLDATE:
872 		return FILE_LEQLDATE;
873 	case FILE_BEQWDATE:
874 		return FILE_LEQWDATE;
875 	case FILE_LESHORT:
876 		return FILE_BESHORT;
877 	case FILE_LELONG:
878 		return FILE_BELONG;
879 	case FILE_LEDATE:
880 		return FILE_BEDATE;
881 	case FILE_LELDATE:
882 		return FILE_BELDATE;
883 	case FILE_LEQUAD:
884 		return FILE_BEQUAD;
885 	case FILE_LEQDATE:
886 		return FILE_BEQDATE;
887 	case FILE_LEQLDATE:
888 		return FILE_BEQLDATE;
889 	case FILE_LEQWDATE:
890 		return FILE_BEQWDATE;
891 	case FILE_BEFLOAT:
892 		return FILE_LEFLOAT;
893 	case FILE_LEFLOAT:
894 		return FILE_BEFLOAT;
895 	case FILE_BEDOUBLE:
896 		return FILE_LEDOUBLE;
897 	case FILE_LEDOUBLE:
898 		return FILE_BEDOUBLE;
899 	default:
900 		return type;
901 	}
902 }
903 #define DO_CVT(fld, cast) \
904 	if (m->num_mask) \
905 		switch (m->mask_op & FILE_OPS_MASK) { \
906 		case FILE_OPAND: \
907 			p->fld &= cast m->num_mask; \
908 			break; \
909 		case FILE_OPOR: \
910 			p->fld |= cast m->num_mask; \
911 			break; \
912 		case FILE_OPXOR: \
913 			p->fld ^= cast m->num_mask; \
914 			break; \
915 		case FILE_OPADD: \
916 			p->fld += cast m->num_mask; \
917 			break; \
918 		case FILE_OPMINUS: \
919 			p->fld -= cast m->num_mask; \
920 			break; \
921 		case FILE_OPMULTIPLY: \
922 			p->fld *= cast m->num_mask; \
923 			break; \
924 		case FILE_OPDIVIDE: \
925 			if (cast m->num_mask == 0) \
926 				return -1; \
927 			p->fld /= cast m->num_mask; \
928 			break; \
929 		case FILE_OPMODULO: \
930 			if (cast m->num_mask == 0) \
931 				return -1; \
932 			p->fld %= cast m->num_mask; \
933 			break; \
934 		} \
935 	if (m->mask_op & FILE_OPINVERSE) \
936 		p->fld = ~p->fld \
937 
938 private int
cvt_8(union VALUETYPE * p,const struct magic * m)939 cvt_8(union VALUETYPE *p, const struct magic *m)
940 {
941 	DO_CVT(b, (uint8_t));
942 	return 0;
943 }
944 
945 private int
cvt_16(union VALUETYPE * p,const struct magic * m)946 cvt_16(union VALUETYPE *p, const struct magic *m)
947 {
948 	DO_CVT(h, (uint16_t));
949 	return 0;
950 }
951 
952 private int
cvt_32(union VALUETYPE * p,const struct magic * m)953 cvt_32(union VALUETYPE *p, const struct magic *m)
954 {
955 	DO_CVT(l, (uint32_t));
956 	return 0;
957 }
958 
959 private int
cvt_64(union VALUETYPE * p,const struct magic * m)960 cvt_64(union VALUETYPE *p, const struct magic *m)
961 {
962 	DO_CVT(q, (uint64_t));
963 	return 0;
964 }
965 
966 #define DO_CVT2(fld, cast) \
967 	if (m->num_mask) \
968 		switch (m->mask_op & FILE_OPS_MASK) { \
969 		case FILE_OPADD: \
970 			p->fld += cast m->num_mask; \
971 			break; \
972 		case FILE_OPMINUS: \
973 			p->fld -= cast m->num_mask; \
974 			break; \
975 		case FILE_OPMULTIPLY: \
976 			p->fld *= cast m->num_mask; \
977 			break; \
978 		case FILE_OPDIVIDE: \
979 			if (cast m->num_mask == 0) \
980 				return -1; \
981 			p->fld /= cast m->num_mask; \
982 			break; \
983 		} \
984 
985 private int
cvt_float(union VALUETYPE * p,const struct magic * m)986 cvt_float(union VALUETYPE *p, const struct magic *m)
987 {
988 	DO_CVT2(f, (float));
989 	return 0;
990 }
991 
992 private int
cvt_double(union VALUETYPE * p,const struct magic * m)993 cvt_double(union VALUETYPE *p, const struct magic *m)
994 {
995 	DO_CVT2(d, (double));
996 	return 0;
997 }
998 
999 /*
1000  * Convert the byte order of the data we are looking at
1001  * While we're here, let's apply the mask operation
1002  * (unless you have a better idea)
1003  */
1004 private int
mconvert(struct magic_set * ms,struct magic * m,int flip)1005 mconvert(struct magic_set *ms, struct magic *m, int flip)
1006 {
1007 	union VALUETYPE *p = &ms->ms_value;
1008 
1009 	switch (cvt_flip(m->type, flip)) {
1010 	case FILE_BYTE:
1011 		if (cvt_8(p, m) == -1)
1012 			goto out;
1013 		return 1;
1014 	case FILE_SHORT:
1015 		if (cvt_16(p, m) == -1)
1016 			goto out;
1017 		return 1;
1018 	case FILE_LONG:
1019 	case FILE_DATE:
1020 	case FILE_LDATE:
1021 		if (cvt_32(p, m) == -1)
1022 			goto out;
1023 		return 1;
1024 	case FILE_QUAD:
1025 	case FILE_QDATE:
1026 	case FILE_QLDATE:
1027 	case FILE_QWDATE:
1028 		if (cvt_64(p, m) == -1)
1029 			goto out;
1030 		return 1;
1031 	case FILE_STRING:
1032 	case FILE_BESTRING16:
1033 	case FILE_LESTRING16: {
1034 		/* Null terminate and eat *trailing* return */
1035 		p->s[sizeof(p->s) - 1] = '\0';
1036 		return 1;
1037 	}
1038 	case FILE_PSTRING: {
1039 		size_t sz = file_pstring_length_size(m);
1040 		char *ptr1 = p->s, *ptr2 = ptr1 + sz;
1041 		size_t len = file_pstring_get_length(m, ptr1);
1042 		sz = sizeof(p->s) - sz; /* maximum length of string */
1043 		if (len >= sz) {
1044 			/*
1045 			 * The size of the pascal string length (sz)
1046 			 * is 1, 2, or 4. We need at least 1 byte for NUL
1047 			 * termination, but we've already truncated the
1048 			 * string by p->s, so we need to deduct sz.
1049 			 * Because we can use one of the bytes of the length
1050 			 * after we shifted as NUL termination.
1051 			 */
1052 			len = sz;
1053 		}
1054 		while (len--)
1055 			*ptr1++ = *ptr2++;
1056 		*ptr1 = '\0';
1057 		return 1;
1058 	}
1059 	case FILE_BESHORT:
1060 		p->h = (short)BE16(p);
1061 		if (cvt_16(p, m) == -1)
1062 			goto out;
1063 		return 1;
1064 	case FILE_BELONG:
1065 	case FILE_BEDATE:
1066 	case FILE_BELDATE:
1067 		p->l = (int32_t)BE32(p);
1068 		if (cvt_32(p, m) == -1)
1069 			goto out;
1070 		return 1;
1071 	case FILE_BEQUAD:
1072 	case FILE_BEQDATE:
1073 	case FILE_BEQLDATE:
1074 	case FILE_BEQWDATE:
1075 		p->q = (uint64_t)BE64(p);
1076 		if (cvt_64(p, m) == -1)
1077 			goto out;
1078 		return 1;
1079 	case FILE_LESHORT:
1080 		p->h = (short)LE16(p);
1081 		if (cvt_16(p, m) == -1)
1082 			goto out;
1083 		return 1;
1084 	case FILE_LELONG:
1085 	case FILE_LEDATE:
1086 	case FILE_LELDATE:
1087 		p->l = (int32_t)LE32(p);
1088 		if (cvt_32(p, m) == -1)
1089 			goto out;
1090 		return 1;
1091 	case FILE_LEQUAD:
1092 	case FILE_LEQDATE:
1093 	case FILE_LEQLDATE:
1094 	case FILE_LEQWDATE:
1095 		p->q = (uint64_t)LE64(p);
1096 		if (cvt_64(p, m) == -1)
1097 			goto out;
1098 		return 1;
1099 	case FILE_MELONG:
1100 	case FILE_MEDATE:
1101 	case FILE_MELDATE:
1102 		p->l = (int32_t)ME32(p);
1103 		if (cvt_32(p, m) == -1)
1104 			goto out;
1105 		return 1;
1106 	case FILE_FLOAT:
1107 		if (cvt_float(p, m) == -1)
1108 			goto out;
1109 		return 1;
1110 	case FILE_BEFLOAT:
1111 		p->l = BE32(p);
1112 		if (cvt_float(p, m) == -1)
1113 			goto out;
1114 		return 1;
1115 	case FILE_LEFLOAT:
1116 		p->l = LE32(p);
1117 		if (cvt_float(p, m) == -1)
1118 			goto out;
1119 		return 1;
1120 	case FILE_DOUBLE:
1121 		if (cvt_double(p, m) == -1)
1122 			goto out;
1123 		return 1;
1124 	case FILE_BEDOUBLE:
1125 		p->q = BE64(p);
1126 		if (cvt_double(p, m) == -1)
1127 			goto out;
1128 		return 1;
1129 	case FILE_LEDOUBLE:
1130 		p->q = LE64(p);
1131 		if (cvt_double(p, m) == -1)
1132 			goto out;
1133 		return 1;
1134 	case FILE_REGEX:
1135 	case FILE_SEARCH:
1136 	case FILE_DEFAULT:
1137 	case FILE_CLEAR:
1138 	case FILE_NAME:
1139 	case FILE_USE:
1140 	case FILE_DER:
1141 		return 1;
1142 	default:
1143 		file_magerror(ms, "invalid type %d in mconvert()", m->type);
1144 		return 0;
1145 	}
1146 out:
1147 	file_magerror(ms, "zerodivide in mconvert()");
1148 	return 0;
1149 }
1150 
1151 
1152 private void
mdebug(uint32_t offset,const char * str,size_t len)1153 mdebug(uint32_t offset, const char *str, size_t len)
1154 {
1155 	(void) fprintf(stderr, "mget/%" SIZE_T_FORMAT "u @%d: ", len, offset);
1156 	file_showstr(stderr, str, len);
1157 	(void) fputc('\n', stderr);
1158 	(void) fputc('\n', stderr);
1159 }
1160 
1161 private int
mcopy(struct magic_set * ms,union VALUETYPE * p,int type,int indir,const unsigned char * s,uint32_t offset,size_t nbytes,struct magic * m)1162 mcopy(struct magic_set *ms, union VALUETYPE *p, int type, int indir,
1163     const unsigned char *s, uint32_t offset, size_t nbytes, struct magic *m)
1164 {
1165 	/*
1166 	 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1167 	 * anything, but setup pointers into the source
1168 	 */
1169 	if (indir == 0) {
1170 		switch (type) {
1171 		case FILE_DER:
1172 		case FILE_SEARCH:
1173 			if (offset > nbytes)
1174 				offset = CAST(uint32_t, nbytes);
1175 			ms->search.s = RCAST(const char *, s) + offset;
1176 			ms->search.s_len = nbytes - offset;
1177 			ms->search.offset = offset;
1178 			return 0;
1179 
1180 		case FILE_REGEX: {
1181 			const char *b;
1182 			const char *c;
1183 			const char *last;	/* end of search region */
1184 			const char *buf;	/* start of search region */
1185 			const char *end;
1186 			size_t lines, linecnt, bytecnt;
1187 
1188 			if (s == NULL) {
1189 				ms->search.s_len = 0;
1190 				ms->search.s = NULL;
1191 				return 0;
1192 			}
1193 
1194 			if (m->str_flags & REGEX_LINE_COUNT) {
1195 				linecnt = m->str_range;
1196 				bytecnt = linecnt * 80;
1197 			} else {
1198 				linecnt = 0;
1199 				bytecnt = m->str_range;
1200 			}
1201 
1202 			if (bytecnt == 0 || bytecnt > nbytes - offset)
1203 				bytecnt = nbytes - offset;
1204 			if (bytecnt > ms->regex_max)
1205 				bytecnt = ms->regex_max;
1206 
1207 			buf = RCAST(const char *, s) + offset;
1208 			end = last = RCAST(const char *, s) + bytecnt + offset;
1209 			/* mget() guarantees buf <= last */
1210 			for (lines = linecnt, b = buf; lines && b < end &&
1211 			     ((b = CAST(const char *,
1212 				 memchr(c = b, '\n', CAST(size_t, (end - b)))))
1213 			     || (b = CAST(const char *,
1214 				 memchr(c, '\r', CAST(size_t, (end - c))))));
1215 			     lines--, b++) {
1216 				last = b;
1217 				if (b < end - 1 && b[0] == '\r' && b[1] == '\n')
1218 					b++;
1219 			}
1220 			if (lines)
1221 				last = RCAST(const char *, s) + bytecnt;
1222 
1223 			ms->search.s = buf;
1224 			ms->search.s_len = last - buf;
1225 			ms->search.offset = offset;
1226 			ms->search.rm_len = 0;
1227 			return 0;
1228 		}
1229 		case FILE_BESTRING16:
1230 		case FILE_LESTRING16: {
1231 			const unsigned char *src = s + offset;
1232 			const unsigned char *esrc = s + nbytes;
1233 			char *dst = p->s;
1234 			char *edst = &p->s[sizeof(p->s) - 1];
1235 
1236 			if (type == FILE_BESTRING16)
1237 				src++;
1238 
1239 			/* check that offset is within range */
1240 			if (offset >= nbytes)
1241 				break;
1242 			for (/*EMPTY*/; src < esrc; src += 2, dst++) {
1243 				if (dst < edst)
1244 					*dst = *src;
1245 				else
1246 					break;
1247 				if (*dst == '\0') {
1248 					if (type == FILE_BESTRING16 ?
1249 					    *(src - 1) != '\0' :
1250 					    ((src + 1 < esrc) &&
1251 					    *(src + 1) != '\0'))
1252 						*dst = ' ';
1253 				}
1254 			}
1255 			*edst = '\0';
1256 			return 0;
1257 		}
1258 		case FILE_STRING:	/* XXX - these two should not need */
1259 		case FILE_PSTRING:	/* to copy anything, but do anyway. */
1260 		default:
1261 			break;
1262 		}
1263 	}
1264 
1265 	if (offset >= nbytes) {
1266 		(void)memset(p, '\0', sizeof(*p));
1267 		return 0;
1268 	}
1269 	if (nbytes - offset < sizeof(*p))
1270 		nbytes = nbytes - offset;
1271 	else
1272 		nbytes = sizeof(*p);
1273 
1274 	(void)memcpy(p, s + offset, nbytes);
1275 
1276 	/*
1277 	 * the usefulness of padding with zeroes eludes me, it
1278 	 * might even cause problems
1279 	 */
1280 	if (nbytes < sizeof(*p))
1281 		(void)memset(((char *)(void *)p) + nbytes, '\0',
1282 		    sizeof(*p) - nbytes);
1283 	return 0;
1284 }
1285 
1286 private uint32_t
do_ops(struct magic * m,intmax_t lhs,intmax_t off)1287 do_ops(struct magic *m, intmax_t lhs, intmax_t off)
1288 {
1289 	intmax_t offset;
1290 	if (off) {
1291 		switch (m->in_op & FILE_OPS_MASK) {
1292 		case FILE_OPAND:
1293 			offset = lhs & off;
1294 			break;
1295 		case FILE_OPOR:
1296 			offset = lhs | off;
1297 			break;
1298 		case FILE_OPXOR:
1299 			offset = lhs ^ off;
1300 			break;
1301 		case FILE_OPADD:
1302 			offset = lhs + off;
1303 			break;
1304 		case FILE_OPMINUS:
1305 			offset = lhs - off;
1306 			break;
1307 		case FILE_OPMULTIPLY:
1308 			offset = lhs * off;
1309 			break;
1310 		case FILE_OPDIVIDE:
1311 			offset = lhs / off;
1312 			break;
1313 		case FILE_OPMODULO:
1314 			offset = lhs % off;
1315 			break;
1316 		}
1317 	} else
1318 		offset = lhs;
1319 	if (m->in_op & FILE_OPINVERSE)
1320 		offset = ~offset;
1321 
1322 	return (uint32_t)offset;
1323 }
1324 
1325 private int
mget(struct magic_set * ms,const unsigned char * s,struct magic * m,size_t nbytes,size_t o,unsigned int cont_level,int mode,int text,int flip,uint16_t * indir_count,uint16_t * name_count,int * printed_something,int * need_separator,int * returnval)1326 mget(struct magic_set *ms, const unsigned char *s, struct magic *m,
1327     size_t nbytes, size_t o, unsigned int cont_level, int mode, int text,
1328     int flip, uint16_t *indir_count, uint16_t *name_count,
1329     int *printed_something, int *need_separator, int *returnval)
1330 {
1331 	uint32_t offset = ms->offset;
1332 	intmax_t lhs;
1333 	file_pushbuf_t *pb;
1334 	int rv, oneed_separator, in_type;
1335 	char *rbuf;
1336 	union VALUETYPE *p = &ms->ms_value;
1337 	struct mlist ml;
1338 
1339 	if (*indir_count >= ms->indir_max) {
1340 		file_error(ms, 0, "indirect count (%hu) exceeded",
1341 		    *indir_count);
1342 		return -1;
1343 	}
1344 
1345 	if (*name_count >= ms->name_max) {
1346 		file_error(ms, 0, "name use count (%hu) exceeded",
1347 		    *name_count);
1348 		return -1;
1349 	}
1350 
1351 	if (mcopy(ms, p, m->type, m->flag & INDIR, s, (uint32_t)(offset + o),
1352 	    (uint32_t)nbytes, m) == -1)
1353 		return -1;
1354 
1355 	if ((ms->flags & MAGIC_DEBUG) != 0) {
1356 		fprintf(stderr, "mget(type=%d, flag=%#x, offset=%u, o=%"
1357 		    SIZE_T_FORMAT "u, " "nbytes=%" SIZE_T_FORMAT
1358 		    "u, il=%hu, nc=%hu)\n",
1359 		    m->type, m->flag, offset, o, nbytes,
1360 		    *indir_count, *name_count);
1361 		mdebug(offset, (char *)(void *)p, sizeof(union VALUETYPE));
1362 	}
1363 
1364 	if (m->flag & INDIR) {
1365 		intmax_t off = m->in_offset;
1366 		const int sgn = m->in_op & FILE_OPSIGNED;
1367 		if (m->in_op & FILE_OPINDIRECT) {
1368 			const union VALUETYPE *q = CAST(const union VALUETYPE *,
1369 			    ((const void *)(s + offset + off)));
1370 			if (OFFSET_OOB(nbytes, offset + off, sizeof(*q)))
1371 				return 0;
1372 			switch (cvt_flip(m->in_type, flip)) {
1373 			case FILE_BYTE:
1374 				off = SEXT(sgn,8,q->b);
1375 				break;
1376 			case FILE_SHORT:
1377 				off = SEXT(sgn,16,q->h);
1378 				break;
1379 			case FILE_BESHORT:
1380 				off = SEXT(sgn,16,BE16(q));
1381 				break;
1382 			case FILE_LESHORT:
1383 				off = SEXT(sgn,16,LE16(q));
1384 				break;
1385 			case FILE_LONG:
1386 				off = SEXT(sgn,32,q->l);
1387 				break;
1388 			case FILE_BELONG:
1389 			case FILE_BEID3:
1390 				off = SEXT(sgn,32,BE32(q));
1391 				break;
1392 			case FILE_LEID3:
1393 			case FILE_LELONG:
1394 				off = SEXT(sgn,32,LE32(q));
1395 				break;
1396 			case FILE_MELONG:
1397 				off = SEXT(sgn,32,ME32(q));
1398 				break;
1399 			}
1400 			if ((ms->flags & MAGIC_DEBUG) != 0)
1401 				fprintf(stderr, "indirect offs=%jd\n", off);
1402 		}
1403 		switch (in_type = cvt_flip(m->in_type, flip)) {
1404 		case FILE_BYTE:
1405 			if (OFFSET_OOB(nbytes, offset, 1))
1406 				return 0;
1407 			offset = do_ops(m, SEXT(sgn,8,p->b), off);
1408 			break;
1409 		case FILE_BESHORT:
1410 			if (OFFSET_OOB(nbytes, offset, 2))
1411 				return 0;
1412 			offset = do_ops(m, SEXT(sgn,16,BE16(p)), off);
1413 			break;
1414 		case FILE_LESHORT:
1415 			if (OFFSET_OOB(nbytes, offset, 2))
1416 				return 0;
1417 			offset = do_ops(m, SEXT(sgn,16,LE16(p)), off);
1418 			break;
1419 		case FILE_SHORT:
1420 			if (OFFSET_OOB(nbytes, offset, 2))
1421 				return 0;
1422 			offset = do_ops(m, SEXT(sgn,16,p->h), off);
1423 			break;
1424 		case FILE_BELONG:
1425 		case FILE_BEID3:
1426 			if (OFFSET_OOB(nbytes, offset, 4))
1427 				return 0;
1428 			lhs = BE32(p);
1429 			if (in_type == FILE_BEID3)
1430 				lhs = cvt_id3(ms, (uint32_t)lhs);
1431 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1432 			break;
1433 		case FILE_LELONG:
1434 		case FILE_LEID3:
1435 			if (OFFSET_OOB(nbytes, offset, 4))
1436 				return 0;
1437 			lhs = LE32(p);
1438 			if (in_type == FILE_LEID3)
1439 				lhs = cvt_id3(ms, (uint32_t)lhs);
1440 			offset = do_ops(m, SEXT(sgn,32,lhs), off);
1441 			break;
1442 		case FILE_MELONG:
1443 			if (OFFSET_OOB(nbytes, offset, 4))
1444 				return 0;
1445 			offset = do_ops(m, SEXT(sgn,32,ME32(p)), off);
1446 			break;
1447 		case FILE_LONG:
1448 			if (OFFSET_OOB(nbytes, offset, 4))
1449 				return 0;
1450 			offset = do_ops(m, SEXT(sgn,32,p->l), off);
1451 			break;
1452 		default:
1453 			break;
1454 		}
1455 
1456 		if (m->flag & INDIROFFADD) {
1457 			offset += ms->c.li[cont_level-1].off;
1458 			if (offset == 0) {
1459 				if ((ms->flags & MAGIC_DEBUG) != 0)
1460 					fprintf(stderr,
1461 					    "indirect *zero* offset\n");
1462 				return 0;
1463 			}
1464 			if ((ms->flags & MAGIC_DEBUG) != 0)
1465 				fprintf(stderr, "indirect +offs=%u\n", offset);
1466 		}
1467 		if (mcopy(ms, p, m->type, 0, s, offset, nbytes, m) == -1)
1468 			return -1;
1469 		ms->offset = offset;
1470 
1471 		if ((ms->flags & MAGIC_DEBUG) != 0) {
1472 			mdebug(offset, (char *)(void *)p,
1473 			    sizeof(union VALUETYPE));
1474 		}
1475 	}
1476 
1477 	/* Verify we have enough data to match magic type */
1478 	switch (m->type) {
1479 	case FILE_BYTE:
1480 		if (OFFSET_OOB(nbytes, offset, 1))
1481 			return 0;
1482 		break;
1483 
1484 	case FILE_SHORT:
1485 	case FILE_BESHORT:
1486 	case FILE_LESHORT:
1487 		if (OFFSET_OOB(nbytes, offset, 2))
1488 			return 0;
1489 		break;
1490 
1491 	case FILE_LONG:
1492 	case FILE_BELONG:
1493 	case FILE_LELONG:
1494 	case FILE_MELONG:
1495 	case FILE_DATE:
1496 	case FILE_BEDATE:
1497 	case FILE_LEDATE:
1498 	case FILE_MEDATE:
1499 	case FILE_LDATE:
1500 	case FILE_BELDATE:
1501 	case FILE_LELDATE:
1502 	case FILE_MELDATE:
1503 	case FILE_FLOAT:
1504 	case FILE_BEFLOAT:
1505 	case FILE_LEFLOAT:
1506 		if (OFFSET_OOB(nbytes, offset, 4))
1507 			return 0;
1508 		break;
1509 
1510 	case FILE_DOUBLE:
1511 	case FILE_BEDOUBLE:
1512 	case FILE_LEDOUBLE:
1513 		if (OFFSET_OOB(nbytes, offset, 8))
1514 			return 0;
1515 		break;
1516 
1517 	case FILE_STRING:
1518 	case FILE_PSTRING:
1519 	case FILE_SEARCH:
1520 		if (OFFSET_OOB(nbytes, offset, m->vallen))
1521 			return 0;
1522 		break;
1523 
1524 	case FILE_REGEX:
1525 		if (nbytes < offset)
1526 			return 0;
1527 		break;
1528 
1529 	case FILE_INDIRECT:
1530 		if (m->str_flags & INDIRECT_RELATIVE)
1531 			offset += CAST(uint32_t, o);
1532 		if (offset == 0)
1533 			return 0;
1534 
1535 		if (nbytes < offset)
1536 			return 0;
1537 
1538 		if ((pb = file_push_buffer(ms)) == NULL)
1539 			return -1;
1540 
1541 		(*indir_count)++;
1542 		rv = file_softmagic(ms, s + offset, nbytes - offset,
1543 		    indir_count, name_count, BINTEST, text);
1544 
1545 		if ((ms->flags & MAGIC_DEBUG) != 0)
1546 			fprintf(stderr, "indirect @offs=%u[%d]\n", offset, rv);
1547 
1548 		rbuf = file_pop_buffer(ms, pb);
1549 		if (rbuf == NULL && ms->event_flags & EVENT_HAD_ERR)
1550 			return -1;
1551 
1552 		if (rv == 1) {
1553 			if ((ms->flags & MAGIC_NODESC) == 0 &&
1554 			    file_printf(ms, F(ms, m, "%u"), offset) == -1) {
1555 				if (rbuf) efree(rbuf);
1556 				return -1;
1557 			}
1558 			if (file_printf(ms, "%s", rbuf) == -1) {
1559 				if (rbuf) efree(rbuf);
1560 				return -1;
1561 			}
1562 		}
1563 		if (rbuf) efree(rbuf);
1564 		return rv;
1565 
1566 	case FILE_USE:
1567 		if (nbytes < offset)
1568 			return 0;
1569 		rbuf = m->value.s;
1570 		if (*rbuf == '^') {
1571 			rbuf++;
1572 			flip = !flip;
1573 		}
1574 		if (file_magicfind(ms, rbuf, &ml) == -1) {
1575 			file_error(ms, 0, "cannot find entry `%s'", rbuf);
1576 			return -1;
1577 		}
1578 		(*name_count)++;
1579 		oneed_separator = *need_separator;
1580 		if (m->flag & NOSPACE)
1581 			*need_separator = 0;
1582 		rv = match(ms, ml.magic, ml.nmagic, s, nbytes, offset + o,
1583 		    mode, text, flip, indir_count, name_count,
1584 		    printed_something, need_separator, returnval);
1585 		if (rv != 1)
1586 		    *need_separator = oneed_separator;
1587 		return 1;
1588 
1589 	case FILE_NAME:
1590 		if (ms->flags & MAGIC_NODESC)
1591 			return 1;
1592 		if (file_printf(ms, "%s", m->desc) == -1)
1593 			return -1;
1594 		return 1;
1595 	case FILE_DER:
1596 	case FILE_DEFAULT:	/* nothing to check */
1597 	case FILE_CLEAR:
1598 	default:
1599 		break;
1600 	}
1601 	if (!mconvert(ms, m, flip))
1602 		return 0;
1603 	return 1;
1604 }
1605 
1606 private uint64_t
file_strncmp(const char * s1,const char * s2,size_t len,uint32_t flags)1607 file_strncmp(const char *s1, const char *s2, size_t len, uint32_t flags)
1608 {
1609 	/*
1610 	 * Convert the source args to unsigned here so that (1) the
1611 	 * compare will be unsigned as it is in strncmp() and (2) so
1612 	 * the ctype functions will work correctly without extra
1613 	 * casting.
1614 	 */
1615 	const unsigned char *a = (const unsigned char *)s1;
1616 	const unsigned char *b = (const unsigned char *)s2;
1617 	const unsigned char *eb = b + len;
1618 	uint64_t v;
1619 
1620 	/*
1621 	 * What we want here is v = strncmp(s1, s2, len),
1622 	 * but ignoring any nulls.
1623 	 */
1624 	v = 0;
1625 	if (0L == flags) { /* normal string: do it fast */
1626 		while (len-- > 0)
1627 			if ((v = *b++ - *a++) != '\0')
1628 				break;
1629 	}
1630 	else { /* combine the others */
1631 		while (len-- > 0) {
1632 			if (b >= eb) {
1633 				v = 1;
1634 				break;
1635 			}
1636 			if ((flags & STRING_IGNORE_LOWERCASE) &&
1637 			    islower(*a)) {
1638 				if ((v = tolower(*b++) - *a++) != '\0')
1639 					break;
1640 			}
1641 			else if ((flags & STRING_IGNORE_UPPERCASE) &&
1642 			    isupper(*a)) {
1643 				if ((v = toupper(*b++) - *a++) != '\0')
1644 					break;
1645 			}
1646 			else if ((flags & STRING_COMPACT_WHITESPACE) &&
1647 			    isspace(*a)) {
1648 				a++;
1649 				if (isspace(*b++)) {
1650 					if (!isspace(*a))
1651 						while (b < eb && isspace(*b))
1652 							b++;
1653 				}
1654 				else {
1655 					v = 1;
1656 					break;
1657 				}
1658 			}
1659 			else if ((flags & STRING_COMPACT_OPTIONAL_WHITESPACE) &&
1660 			    isspace(*a)) {
1661 				a++;
1662 				while (b < eb && isspace(*b))
1663 					b++;
1664 			}
1665 			else {
1666 				if ((v = *b++ - *a++) != '\0')
1667 					break;
1668 			}
1669 		}
1670 	}
1671 	return v;
1672 }
1673 
1674 private uint64_t
file_strncmp16(const char * a,const char * b,size_t len,uint32_t flags)1675 file_strncmp16(const char *a, const char *b, size_t len, uint32_t flags)
1676 {
1677 	/*
1678 	 * XXX - The 16-bit string compare probably needs to be done
1679 	 * differently, especially if the flags are to be supported.
1680 	 * At the moment, I am unsure.
1681 	 */
1682 	flags = 0;
1683 	return file_strncmp(a, b, len, flags);
1684 }
1685 
1686 public void
convert_libmagic_pattern(zval * pattern,char * val,int len,int options)1687 convert_libmagic_pattern(zval *pattern, char *val, int len, int options)
1688 {
1689 	int i, j=0;
1690 	zend_string *t;
1691 
1692 	t = zend_string_alloc(len * 2 + 4, 0);
1693 
1694 	ZSTR_VAL(t)[j++] = '~';
1695 
1696 	for (i = 0; i < len; i++, j++) {
1697 		switch (val[i]) {
1698 			case '~':
1699 				ZSTR_VAL(t)[j++] = '\\';
1700 				ZSTR_VAL(t)[j] = '~';
1701 				break;
1702 			default:
1703 				ZSTR_VAL(t)[j] = val[i];
1704 				break;
1705 		}
1706 	}
1707 	ZSTR_VAL(t)[j++] = '~';
1708 
1709 	if (options & PCRE_CASELESS)
1710 		ZSTR_VAL(t)[j++] = 'i';
1711 
1712 	if (options & PCRE_MULTILINE)
1713 		ZSTR_VAL(t)[j++] = 'm';
1714 
1715 	ZSTR_VAL(t)[j]='\0';
1716 	ZSTR_LEN(t) = j;
1717 
1718 	ZVAL_NEW_STR(pattern, t);
1719 }
1720 
1721 private int
magiccheck(struct magic_set * ms,struct magic * m)1722 magiccheck(struct magic_set *ms, struct magic *m)
1723 {
1724 	uint64_t l = m->value.q;
1725 	uint64_t v;
1726 	float fl, fv;
1727 	double dl, dv;
1728 	int matched;
1729 	union VALUETYPE *p = &ms->ms_value;
1730 
1731 	switch (m->type) {
1732 	case FILE_BYTE:
1733 		v = p->b;
1734 		break;
1735 
1736 	case FILE_SHORT:
1737 	case FILE_BESHORT:
1738 	case FILE_LESHORT:
1739 		v = p->h;
1740 		break;
1741 
1742 	case FILE_LONG:
1743 	case FILE_BELONG:
1744 	case FILE_LELONG:
1745 	case FILE_MELONG:
1746 	case FILE_DATE:
1747 	case FILE_BEDATE:
1748 	case FILE_LEDATE:
1749 	case FILE_MEDATE:
1750 	case FILE_LDATE:
1751 	case FILE_BELDATE:
1752 	case FILE_LELDATE:
1753 	case FILE_MELDATE:
1754 		v = p->l;
1755 		break;
1756 
1757 	case FILE_QUAD:
1758 	case FILE_LEQUAD:
1759 	case FILE_BEQUAD:
1760 	case FILE_QDATE:
1761 	case FILE_BEQDATE:
1762 	case FILE_LEQDATE:
1763 	case FILE_QLDATE:
1764 	case FILE_BEQLDATE:
1765 	case FILE_LEQLDATE:
1766 	case FILE_QWDATE:
1767 	case FILE_BEQWDATE:
1768 	case FILE_LEQWDATE:
1769 		v = p->q;
1770 		break;
1771 
1772 	case FILE_FLOAT:
1773 	case FILE_BEFLOAT:
1774 	case FILE_LEFLOAT:
1775 		fl = m->value.f;
1776 		fv = p->f;
1777 		switch (m->reln) {
1778 		case 'x':
1779 			matched = 1;
1780 			break;
1781 
1782 		case '!':
1783 			matched = fv != fl;
1784 			break;
1785 
1786 		case '=':
1787 			matched = fv == fl;
1788 			break;
1789 
1790 		case '>':
1791 			matched = fv > fl;
1792 			break;
1793 
1794 		case '<':
1795 			matched = fv < fl;
1796 			break;
1797 
1798 		default:
1799 			file_magerror(ms, "cannot happen with float: invalid relation `%c'",
1800 			    m->reln);
1801 			return -1;
1802 		}
1803 		return matched;
1804 
1805 	case FILE_DOUBLE:
1806 	case FILE_BEDOUBLE:
1807 	case FILE_LEDOUBLE:
1808 		dl = m->value.d;
1809 		dv = p->d;
1810 		switch (m->reln) {
1811 		case 'x':
1812 			matched = 1;
1813 			break;
1814 
1815 		case '!':
1816 			matched = dv != dl;
1817 			break;
1818 
1819 		case '=':
1820 			matched = dv == dl;
1821 			break;
1822 
1823 		case '>':
1824 			matched = dv > dl;
1825 			break;
1826 
1827 		case '<':
1828 			matched = dv < dl;
1829 			break;
1830 
1831 		default:
1832 			file_magerror(ms, "cannot happen with double: invalid relation `%c'", m->reln);
1833 			return -1;
1834 		}
1835 		return matched;
1836 
1837 	case FILE_DEFAULT:
1838 	case FILE_CLEAR:
1839 		l = 0;
1840 		v = 0;
1841 		break;
1842 
1843 	case FILE_STRING:
1844 	case FILE_PSTRING:
1845 		l = 0;
1846 		v = file_strncmp(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1847 		break;
1848 
1849 	case FILE_BESTRING16:
1850 	case FILE_LESTRING16:
1851 		l = 0;
1852 		v = file_strncmp16(m->value.s, p->s, (size_t)m->vallen, m->str_flags);
1853 		break;
1854 
1855 	case FILE_SEARCH: { /* search ms->search.s for the string m->value.s */
1856 		size_t slen;
1857 		size_t idx;
1858 
1859 		if (ms->search.s == NULL)
1860 			return 0;
1861 
1862 		slen = MIN(m->vallen, sizeof(m->value.s));
1863 		l = 0;
1864 		v = 0;
1865 
1866 		for (idx = 0; m->str_range == 0 || idx < m->str_range; idx++) {
1867 			if (slen + idx > ms->search.s_len)
1868 				return 0;
1869 
1870 			v = file_strncmp(m->value.s, ms->search.s + idx, slen,
1871 			    m->str_flags);
1872 			if (v == 0) {	/* found match */
1873 				ms->search.offset += idx;
1874 				ms->search.rm_len = ms->search.s_len - idx;
1875 				break;
1876 			}
1877 		}
1878 		break;
1879 	}
1880 	case FILE_REGEX: {
1881 		zval pattern;
1882 		int options = 0;
1883 		pcre_cache_entry *pce;
1884 
1885 		options |= PCRE_MULTILINE;
1886 
1887 		if (m->str_flags & STRING_IGNORE_CASE) {
1888 			options |= PCRE_CASELESS;
1889 		}
1890 
1891 		convert_libmagic_pattern(&pattern, (char *)m->value.s, m->vallen, options);
1892 
1893 		l = v = 0;
1894 		if ((pce = pcre_get_compiled_regex_cache(Z_STR(pattern))) == NULL) {
1895 			zval_ptr_dtor(&pattern);
1896 			return -1;
1897 		} else {
1898 			/* pce now contains the compiled regex */
1899 			zval retval;
1900 			zval subpats;
1901 			char *haystack;
1902 
1903 			ZVAL_NULL(&retval);
1904 			ZVAL_NULL(&subpats);
1905 
1906 			/* Cut the search len from haystack, equals to REG_STARTEND */
1907 			haystack = estrndup(ms->search.s, ms->search.s_len);
1908 
1909 			/* match v = 0, no match v = 1 */
1910 			php_pcre_match_impl(pce, haystack, ms->search.s_len, &retval, &subpats, 0, 1, PREG_OFFSET_CAPTURE, 0);
1911 			/* Free haystack */
1912 			efree(haystack);
1913 
1914 			if (Z_LVAL(retval) < 0) {
1915 				zval_ptr_dtor(&subpats);
1916 				zval_ptr_dtor(&pattern);
1917 				return -1;
1918 			} else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) {
1919 				/* Need to fetch global match which equals pmatch[0] */
1920 				zval *pzval;
1921 				HashTable *ht = Z_ARRVAL(subpats);
1922 				if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) {
1923 					/* If everything goes according to the master plan
1924 					   tmpcopy now contains two elements:
1925 					   0 = the match
1926 					   1 = starting position of the match */
1927 					zval *match, *offset;
1928 					if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) &&
1929 							(offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) {
1930 						if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) {
1931 							goto error_out;
1932 						}
1933 						ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */
1934 						ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */
1935 						ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */;
1936 						v = 0;
1937 					} else {
1938 						goto error_out;
1939 					}
1940 				} else {
1941 error_out:
1942 					zval_ptr_dtor(&subpats);
1943 					zval_ptr_dtor(&pattern);
1944 					return -1;
1945 				}
1946 			} else {
1947 				v = 1;
1948 			}
1949 			zval_ptr_dtor(&subpats);
1950 			zval_ptr_dtor(&pattern);
1951 		}
1952 		break;
1953 	}
1954 	case FILE_INDIRECT:
1955 	case FILE_USE:
1956 	case FILE_NAME:
1957 		return 1;
1958 	case FILE_DER:
1959 		matched = der_cmp(ms, m);
1960 		if (matched == -1) {
1961 			if ((ms->flags & MAGIC_DEBUG) != 0) {
1962 				(void) fprintf(stderr,
1963 				    "EOF comparing DER entries");
1964 			}
1965 			return 0;
1966 		}
1967 		return matched;
1968 	default:
1969 		file_magerror(ms, "invalid type %d in magiccheck()", m->type);
1970 		return -1;
1971 	}
1972 
1973 	v = file_signextend(ms, m, v);
1974 
1975 	switch (m->reln) {
1976 	case 'x':
1977 		if ((ms->flags & MAGIC_DEBUG) != 0)
1978 			(void) fprintf(stderr, "%" INT64_T_FORMAT
1979 			    "u == *any* = 1\n", (unsigned long long)v);
1980 		matched = 1;
1981 		break;
1982 
1983 	case '!':
1984 		matched = v != l;
1985 		if ((ms->flags & MAGIC_DEBUG) != 0)
1986 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u != %"
1987 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1988 			    (unsigned long long)l, matched);
1989 		break;
1990 
1991 	case '=':
1992 		matched = v == l;
1993 		if ((ms->flags & MAGIC_DEBUG) != 0)
1994 			(void) fprintf(stderr, "%" INT64_T_FORMAT "u == %"
1995 			    INT64_T_FORMAT "u = %d\n", (unsigned long long)v,
1996 			    (unsigned long long)l, matched);
1997 		break;
1998 
1999 	case '>':
2000 		if (m->flag & UNSIGNED) {
2001 			matched = v > l;
2002 			if ((ms->flags & MAGIC_DEBUG) != 0)
2003 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2004 				    "u > %" INT64_T_FORMAT "u = %d\n",
2005 				    (unsigned long long)v,
2006 				    (unsigned long long)l, matched);
2007 		}
2008 		else {
2009 			matched = (int64_t) v > (int64_t) l;
2010 			if ((ms->flags & MAGIC_DEBUG) != 0)
2011 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2012 				    "d > %" INT64_T_FORMAT "d = %d\n",
2013 				    (long long)v, (long long)l, matched);
2014 		}
2015 		break;
2016 
2017 	case '<':
2018 		if (m->flag & UNSIGNED) {
2019 			matched = v < l;
2020 			if ((ms->flags & MAGIC_DEBUG) != 0)
2021 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2022 				    "u < %" INT64_T_FORMAT "u = %d\n",
2023 				    (unsigned long long)v,
2024 				    (unsigned long long)l, matched);
2025 		}
2026 		else {
2027 			matched = (int64_t) v < (int64_t) l;
2028 			if ((ms->flags & MAGIC_DEBUG) != 0)
2029 				(void) fprintf(stderr, "%" INT64_T_FORMAT
2030 				    "d < %" INT64_T_FORMAT "d = %d\n",
2031 				     (long long)v, (long long)l, matched);
2032 		}
2033 		break;
2034 
2035 	case '&':
2036 		matched = (v & l) == l;
2037 		if ((ms->flags & MAGIC_DEBUG) != 0)
2038 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2039 			    INT64_T_FORMAT "x) == %" INT64_T_FORMAT
2040 			    "x) = %d\n", (unsigned long long)v,
2041 			    (unsigned long long)l, (unsigned long long)l,
2042 			    matched);
2043 		break;
2044 
2045 	case '^':
2046 		matched = (v & l) != l;
2047 		if ((ms->flags & MAGIC_DEBUG) != 0)
2048 			(void) fprintf(stderr, "((%" INT64_T_FORMAT "x & %"
2049 			    INT64_T_FORMAT "x) != %" INT64_T_FORMAT
2050 			    "x) = %d\n", (unsigned long long)v,
2051 			    (unsigned long long)l, (unsigned long long)l,
2052 			    matched);
2053 		break;
2054 
2055 	default:
2056 		file_magerror(ms, "cannot happen: invalid relation `%c'",
2057 		    m->reln);
2058 		return -1;
2059 	}
2060 
2061 	return matched;
2062 }
2063 
2064 private int
handle_annotation(struct magic_set * ms,struct magic * m,int firstline)2065 handle_annotation(struct magic_set *ms, struct magic *m, int firstline)
2066 {
2067 	if ((ms->flags & MAGIC_APPLE) && m->apple[0]) {
2068 		if (!firstline && file_printf(ms, "\n- ") == -1)
2069 			return -1;
2070 		if (file_printf(ms, "%.8s", m->apple) == -1)
2071 			return -1;
2072 		return 1;
2073 	}
2074 	if ((ms->flags & MAGIC_EXTENSION) && m->ext[0]) {
2075 		if (!firstline && file_printf(ms, "\n- ") == -1)
2076 			return -1;
2077 		if (file_printf(ms, "%s", m->ext) == -1)
2078 			return -1;
2079 		return 1;
2080 	}
2081 	if ((ms->flags & MAGIC_MIME_TYPE) && m->mimetype[0]) {
2082 		if (!firstline && file_printf(ms, "\n- ") == -1)
2083 			return -1;
2084 		if (file_printf(ms, "%s", m->mimetype) == -1)
2085 			return -1;
2086 		return 1;
2087 	}
2088 	return 0;
2089 }
2090 
2091 private int
print_sep(struct magic_set * ms,int firstline)2092 print_sep(struct magic_set *ms, int firstline)
2093 {
2094 //	if (ms->flags & MAGIC_NODESC)
2095 //		return 0;
2096 	if (firstline)
2097 		return 0;
2098 	/*
2099 	 * we found another match
2100 	 * put a newline and '-' to do some simple formatting
2101 	 */
2102 	return file_printf(ms, "\n- ");
2103 }
2104