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