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