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