1*de3a6565Sbrynet /* $OpenBSD: magic-load.c,v 1.26 2017/07/02 10:58:15 brynet Exp $ */
2ff772f70Snicm
3ff772f70Snicm /*
4ff772f70Snicm * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
5ff772f70Snicm *
6ff772f70Snicm * Permission to use, copy, modify, and distribute this software for any
7ff772f70Snicm * purpose with or without fee is hereby granted, provided that the above
8ff772f70Snicm * copyright notice and this permission notice appear in all copies.
9ff772f70Snicm *
10ff772f70Snicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ff772f70Snicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ff772f70Snicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ff772f70Snicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ff772f70Snicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15ff772f70Snicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16ff772f70Snicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ff772f70Snicm */
18ff772f70Snicm
19ff772f70Snicm #include <sys/types.h>
20ff772f70Snicm
21ff772f70Snicm #include <ctype.h>
22*de3a6565Sbrynet #include <err.h>
23ff772f70Snicm #include <errno.h>
24ff772f70Snicm #include <limits.h>
25ff772f70Snicm #include <regex.h>
26ff772f70Snicm #include <stdarg.h>
27ff772f70Snicm #include <stdio.h>
28ff772f70Snicm #include <stdlib.h>
29ff772f70Snicm #include <string.h>
30ff772f70Snicm
31ff772f70Snicm #include "magic.h"
32ff772f70Snicm #include "xmalloc.h"
33ff772f70Snicm
34ff772f70Snicm static int
magic_odigit(u_char c)35ff772f70Snicm magic_odigit(u_char c)
36ff772f70Snicm {
37ff772f70Snicm if (c >= '0' && c <= '7')
38ff772f70Snicm return (c - '0');
39ff772f70Snicm return (-1);
40ff772f70Snicm }
41ff772f70Snicm
42ff772f70Snicm static int
magic_xdigit(u_char c)43ff772f70Snicm magic_xdigit(u_char c)
44ff772f70Snicm {
45ff772f70Snicm if (c >= '0' && c <= '9')
46ff772f70Snicm return (c - '0');
47ff772f70Snicm if (c >= 'a' && c <= 'f')
48ff772f70Snicm return (10 + c - 'a');
49ff772f70Snicm if (c >= 'A' && c <= 'F')
50ff772f70Snicm return (10 + c - 'A');
51ff772f70Snicm return (-1);
52ff772f70Snicm }
53ff772f70Snicm
54ff772f70Snicm static void
magic_mark_text(struct magic_line * ml,int text)55ff772f70Snicm magic_mark_text(struct magic_line *ml, int text)
56ff772f70Snicm {
57ff772f70Snicm do {
58ff772f70Snicm ml->text = text;
59ff772f70Snicm ml = ml->parent;
60ff772f70Snicm } while (ml != NULL);
61ff772f70Snicm }
62ff772f70Snicm
63ff772f70Snicm static int
magic_make_pattern(struct magic_line * ml,const char * name,regex_t * re,const char * p)64ff772f70Snicm magic_make_pattern(struct magic_line *ml, const char *name, regex_t *re,
65ff772f70Snicm const char *p)
66ff772f70Snicm {
67ff772f70Snicm int error;
68ff772f70Snicm char errbuf[256];
69ff772f70Snicm
70ff772f70Snicm error = regcomp(re, p, REG_EXTENDED|REG_NOSUB);
71ff772f70Snicm if (error != 0) {
72ff772f70Snicm regerror(error, re, errbuf, sizeof errbuf);
73ff772f70Snicm magic_warn(ml, "bad %s pattern: %s", name, errbuf);
74ff772f70Snicm return (-1);
75ff772f70Snicm }
76ff772f70Snicm return (0);
77ff772f70Snicm }
78ff772f70Snicm
79ff772f70Snicm static int
magic_set_result(struct magic_line * ml,const char * s)80ff772f70Snicm magic_set_result(struct magic_line *ml, const char *s)
81ff772f70Snicm {
82d8e84ae2Snicm const char *fmt, *endfmt, *cp;
83ff772f70Snicm regex_t *re = NULL;
84ff772f70Snicm regmatch_t pmatch;
85ff772f70Snicm size_t fmtlen;
86ff772f70Snicm
87ff772f70Snicm while (isspace((u_char)*s))
88ff772f70Snicm s++;
89ff772f70Snicm if (*s == '\0') {
90ff772f70Snicm ml->result = NULL;
91ff772f70Snicm return (0);
92ff772f70Snicm }
93ff772f70Snicm ml->result = xstrdup(s);
94ff772f70Snicm
95ff772f70Snicm fmt = NULL;
96ff772f70Snicm for (cp = s; *cp != '\0'; cp++) {
97ff772f70Snicm if (cp[0] == '%' && cp[1] != '%') {
98ff772f70Snicm if (fmt != NULL) {
99ff772f70Snicm magic_warn(ml, "multiple formats");
100ff772f70Snicm return (-1);
101ff772f70Snicm }
102ff772f70Snicm fmt = cp;
103ff772f70Snicm }
104ff772f70Snicm }
105ff772f70Snicm if (fmt == NULL)
106ff772f70Snicm return (0);
107ff772f70Snicm fmt++;
108ff772f70Snicm
109ff772f70Snicm for (endfmt = fmt; *endfmt != '\0'; endfmt++) {
110ff772f70Snicm if (strchr("diouxXeEfFgGsc", *endfmt) != NULL)
111ff772f70Snicm break;
112ff772f70Snicm }
113ff772f70Snicm if (*endfmt == '\0') {
114ff772f70Snicm magic_warn(ml, "unterminated format");
115ff772f70Snicm return (-1);
116ff772f70Snicm }
117ff772f70Snicm fmtlen = endfmt + 1 - fmt;
118ff772f70Snicm if (fmtlen > 32) {
119ff772f70Snicm magic_warn(ml, "format too long");
120ff772f70Snicm return (-1);
121ff772f70Snicm }
122ff772f70Snicm
123ff772f70Snicm if (*endfmt == 's') {
124ff772f70Snicm switch (ml->type) {
125ff772f70Snicm case MAGIC_TYPE_DATE:
126ff772f70Snicm case MAGIC_TYPE_LDATE:
127ff772f70Snicm case MAGIC_TYPE_UDATE:
128ff772f70Snicm case MAGIC_TYPE_ULDATE:
129ff772f70Snicm case MAGIC_TYPE_BEDATE:
130ff772f70Snicm case MAGIC_TYPE_BELDATE:
131ff772f70Snicm case MAGIC_TYPE_UBEDATE:
132ff772f70Snicm case MAGIC_TYPE_UBELDATE:
133ff772f70Snicm case MAGIC_TYPE_QDATE:
134ff772f70Snicm case MAGIC_TYPE_QLDATE:
135ff772f70Snicm case MAGIC_TYPE_UQDATE:
136ff772f70Snicm case MAGIC_TYPE_UQLDATE:
137ff772f70Snicm case MAGIC_TYPE_BEQDATE:
138ff772f70Snicm case MAGIC_TYPE_BEQLDATE:
139ff772f70Snicm case MAGIC_TYPE_UBEQDATE:
140ff772f70Snicm case MAGIC_TYPE_UBEQLDATE:
141ff772f70Snicm case MAGIC_TYPE_LEQDATE:
142ff772f70Snicm case MAGIC_TYPE_LEQLDATE:
143ff772f70Snicm case MAGIC_TYPE_ULEQDATE:
144ff772f70Snicm case MAGIC_TYPE_ULEQLDATE:
145ff772f70Snicm case MAGIC_TYPE_LEDATE:
146ff772f70Snicm case MAGIC_TYPE_LELDATE:
147ff772f70Snicm case MAGIC_TYPE_ULEDATE:
148ff772f70Snicm case MAGIC_TYPE_ULELDATE:
149ff772f70Snicm case MAGIC_TYPE_MEDATE:
150ff772f70Snicm case MAGIC_TYPE_MELDATE:
151ff772f70Snicm case MAGIC_TYPE_STRING:
152ff772f70Snicm case MAGIC_TYPE_PSTRING:
153ff772f70Snicm case MAGIC_TYPE_BESTRING16:
154ff772f70Snicm case MAGIC_TYPE_LESTRING16:
155ff772f70Snicm case MAGIC_TYPE_REGEX:
156ff772f70Snicm case MAGIC_TYPE_SEARCH:
157ff772f70Snicm break;
158ff772f70Snicm default:
159ff772f70Snicm ml->stringify = 1;
160ff772f70Snicm break;
161ff772f70Snicm }
162ff772f70Snicm }
163ff772f70Snicm
164ff772f70Snicm if (!ml->root->compiled) {
165ff772f70Snicm /*
166ff772f70Snicm * XXX %ld (and %lu and so on) is invalid on 64-bit platforms
167ff772f70Snicm * with byte, short, long. We get lucky because our first and
168ff772f70Snicm * only argument ends up in a register. Accept it for now.
169ff772f70Snicm */
170ff772f70Snicm if (magic_make_pattern(ml, "short", &ml->root->format_short,
171ff772f70Snicm "^-?[0-9]*(\\.[0-9]*)?(c|(l|h|hh)?[iduxX])$") != 0)
172ff772f70Snicm return (-1);
173ff772f70Snicm if (magic_make_pattern(ml, "long", &ml->root->format_long,
174ff772f70Snicm "^-?[0-9]*(\\.[0-9]*)?(c|(l|h|hh)?[iduxX])$") != 0)
175ff772f70Snicm return (-1);
176ff772f70Snicm if (magic_make_pattern(ml, "quad", &ml->root->format_quad,
177ff772f70Snicm "^-?[0-9]*(\\.[0-9]*)?ll[iduxX]$") != 0)
178ff772f70Snicm return (-1);
179ff772f70Snicm if (magic_make_pattern(ml, "float", &ml->root->format_float,
180ff772f70Snicm "^-?[0-9]*(\\.[0-9]*)?[eEfFgG]$") != 0)
181ff772f70Snicm return (-1);
182ff772f70Snicm if (magic_make_pattern(ml, "string", &ml->root->format_string,
183ff772f70Snicm "^-?[0-9]*(\\.[0-9]*)?s$") != 0)
184ff772f70Snicm return (-1);
185ff772f70Snicm ml->root->compiled = 1;
186ff772f70Snicm }
187ff772f70Snicm
188ff772f70Snicm if (ml->stringify)
189ff772f70Snicm re = &ml->root->format_string;
190ff772f70Snicm else {
191ff772f70Snicm switch (ml->type) {
192ff772f70Snicm case MAGIC_TYPE_NONE:
193f1123c49Snicm case MAGIC_TYPE_BESTRING16:
194f1123c49Snicm case MAGIC_TYPE_LESTRING16:
195c673ceb0Snicm case MAGIC_TYPE_NAME:
196c673ceb0Snicm case MAGIC_TYPE_USE:
197ff772f70Snicm return (0); /* don't use result */
198ff772f70Snicm case MAGIC_TYPE_BYTE:
199ff772f70Snicm case MAGIC_TYPE_UBYTE:
200ff772f70Snicm case MAGIC_TYPE_SHORT:
201ff772f70Snicm case MAGIC_TYPE_USHORT:
202ff772f70Snicm case MAGIC_TYPE_BESHORT:
203ff772f70Snicm case MAGIC_TYPE_UBESHORT:
204ff772f70Snicm case MAGIC_TYPE_LESHORT:
205ff772f70Snicm case MAGIC_TYPE_ULESHORT:
206ff772f70Snicm re = &ml->root->format_short;
207ff772f70Snicm break;
208ff772f70Snicm case MAGIC_TYPE_LONG:
209ff772f70Snicm case MAGIC_TYPE_ULONG:
210ff772f70Snicm case MAGIC_TYPE_BELONG:
211ff772f70Snicm case MAGIC_TYPE_UBELONG:
212ff772f70Snicm case MAGIC_TYPE_LELONG:
213ff772f70Snicm case MAGIC_TYPE_ULELONG:
214ff772f70Snicm case MAGIC_TYPE_MELONG:
215ff772f70Snicm re = &ml->root->format_long;
216ff772f70Snicm break;
217ff772f70Snicm case MAGIC_TYPE_QUAD:
218ff772f70Snicm case MAGIC_TYPE_UQUAD:
219ff772f70Snicm case MAGIC_TYPE_BEQUAD:
220ff772f70Snicm case MAGIC_TYPE_UBEQUAD:
221ff772f70Snicm case MAGIC_TYPE_LEQUAD:
222ff772f70Snicm case MAGIC_TYPE_ULEQUAD:
223ff772f70Snicm re = &ml->root->format_quad;
224ff772f70Snicm break;
225ff772f70Snicm case MAGIC_TYPE_FLOAT:
226ff772f70Snicm case MAGIC_TYPE_BEFLOAT:
227ff772f70Snicm case MAGIC_TYPE_LEFLOAT:
228ff772f70Snicm case MAGIC_TYPE_DOUBLE:
229ff772f70Snicm case MAGIC_TYPE_BEDOUBLE:
230ff772f70Snicm case MAGIC_TYPE_LEDOUBLE:
231ff772f70Snicm re = &ml->root->format_float;
232ff772f70Snicm break;
233ff772f70Snicm case MAGIC_TYPE_DATE:
234ff772f70Snicm case MAGIC_TYPE_LDATE:
235ff772f70Snicm case MAGIC_TYPE_UDATE:
236ff772f70Snicm case MAGIC_TYPE_ULDATE:
237ff772f70Snicm case MAGIC_TYPE_BEDATE:
238ff772f70Snicm case MAGIC_TYPE_BELDATE:
239ff772f70Snicm case MAGIC_TYPE_UBEDATE:
240ff772f70Snicm case MAGIC_TYPE_UBELDATE:
241ff772f70Snicm case MAGIC_TYPE_QDATE:
242ff772f70Snicm case MAGIC_TYPE_QLDATE:
243ff772f70Snicm case MAGIC_TYPE_UQDATE:
244ff772f70Snicm case MAGIC_TYPE_UQLDATE:
245ff772f70Snicm case MAGIC_TYPE_BEQDATE:
246ff772f70Snicm case MAGIC_TYPE_BEQLDATE:
247ff772f70Snicm case MAGIC_TYPE_UBEQDATE:
248ff772f70Snicm case MAGIC_TYPE_UBEQLDATE:
249ff772f70Snicm case MAGIC_TYPE_LEQDATE:
250ff772f70Snicm case MAGIC_TYPE_LEQLDATE:
251ff772f70Snicm case MAGIC_TYPE_ULEQDATE:
252ff772f70Snicm case MAGIC_TYPE_ULEQLDATE:
253ff772f70Snicm case MAGIC_TYPE_LEDATE:
254ff772f70Snicm case MAGIC_TYPE_LELDATE:
255ff772f70Snicm case MAGIC_TYPE_ULEDATE:
256ff772f70Snicm case MAGIC_TYPE_ULELDATE:
257ff772f70Snicm case MAGIC_TYPE_MEDATE:
258ff772f70Snicm case MAGIC_TYPE_MELDATE:
259ff772f70Snicm case MAGIC_TYPE_STRING:
260ff772f70Snicm case MAGIC_TYPE_PSTRING:
261ff772f70Snicm case MAGIC_TYPE_REGEX:
262ff772f70Snicm case MAGIC_TYPE_SEARCH:
263e0a3e3d1Snicm case MAGIC_TYPE_DEFAULT:
264e0a3e3d1Snicm case MAGIC_TYPE_CLEAR:
265ff772f70Snicm re = &ml->root->format_string;
266ff772f70Snicm break;
267ff772f70Snicm }
268ff772f70Snicm }
269ff772f70Snicm
270ff772f70Snicm pmatch.rm_so = 0;
271ff772f70Snicm pmatch.rm_eo = fmtlen;
272ff772f70Snicm if (regexec(re, fmt, 1, &pmatch, REG_STARTEND) != 0) {
273ff772f70Snicm magic_warn(ml, "bad format for %s: %%%.*s", ml->type_string,
274ff772f70Snicm (int)fmtlen, fmt);
275ff772f70Snicm return (-1);
276ff772f70Snicm }
277ff772f70Snicm
278ff772f70Snicm return (0);
279ff772f70Snicm }
280ff772f70Snicm
281ff772f70Snicm static u_int
magic_get_strength(struct magic_line * ml)282ff772f70Snicm magic_get_strength(struct magic_line *ml)
283ff772f70Snicm {
284ff772f70Snicm int n;
285ff772f70Snicm size_t size;
286ff772f70Snicm
287853bdbd5Snicm if (ml->type == MAGIC_TYPE_NONE)
288853bdbd5Snicm return (0);
289853bdbd5Snicm
290cd410a1eSnicm if (ml->test_not || ml->test_operator == 'x') {
291cd410a1eSnicm n = 1;
292cd410a1eSnicm goto skip;
293cd410a1eSnicm }
294ff772f70Snicm
2950d6e116bSnicm n = 2 * MAGIC_STRENGTH_MULTIPLIER;
296ff772f70Snicm switch (ml->type) {
297ff772f70Snicm case MAGIC_TYPE_NONE:
298ff772f70Snicm case MAGIC_TYPE_DEFAULT:
299ff772f70Snicm return (0);
300e0a3e3d1Snicm case MAGIC_TYPE_CLEAR:
301c673ceb0Snicm case MAGIC_TYPE_NAME:
302c673ceb0Snicm case MAGIC_TYPE_USE:
303e0a3e3d1Snicm break;
304ff772f70Snicm case MAGIC_TYPE_BYTE:
305ff772f70Snicm case MAGIC_TYPE_UBYTE:
306ff772f70Snicm n += 1 * MAGIC_STRENGTH_MULTIPLIER;
307ff772f70Snicm break;
308ff772f70Snicm case MAGIC_TYPE_SHORT:
309ff772f70Snicm case MAGIC_TYPE_USHORT:
310ff772f70Snicm case MAGIC_TYPE_BESHORT:
311ff772f70Snicm case MAGIC_TYPE_UBESHORT:
312ff772f70Snicm case MAGIC_TYPE_LESHORT:
313ff772f70Snicm case MAGIC_TYPE_ULESHORT:
314ff772f70Snicm n += 2 * MAGIC_STRENGTH_MULTIPLIER;
315ff772f70Snicm break;
316ff772f70Snicm case MAGIC_TYPE_LONG:
317ff772f70Snicm case MAGIC_TYPE_ULONG:
318ff772f70Snicm case MAGIC_TYPE_FLOAT:
319ff772f70Snicm case MAGIC_TYPE_DATE:
320ff772f70Snicm case MAGIC_TYPE_LDATE:
321ff772f70Snicm case MAGIC_TYPE_UDATE:
322ff772f70Snicm case MAGIC_TYPE_ULDATE:
323ff772f70Snicm case MAGIC_TYPE_BELONG:
324ff772f70Snicm case MAGIC_TYPE_UBELONG:
325ff772f70Snicm case MAGIC_TYPE_BEFLOAT:
326ff772f70Snicm case MAGIC_TYPE_BEDATE:
327ff772f70Snicm case MAGIC_TYPE_BELDATE:
328ff772f70Snicm case MAGIC_TYPE_UBEDATE:
329ff772f70Snicm case MAGIC_TYPE_UBELDATE:
330ff772f70Snicm n += 4 * MAGIC_STRENGTH_MULTIPLIER;
331ff772f70Snicm break;
332ff772f70Snicm case MAGIC_TYPE_QUAD:
333ff772f70Snicm case MAGIC_TYPE_UQUAD:
334ff772f70Snicm case MAGIC_TYPE_DOUBLE:
335ff772f70Snicm case MAGIC_TYPE_QDATE:
336ff772f70Snicm case MAGIC_TYPE_QLDATE:
337ff772f70Snicm case MAGIC_TYPE_UQDATE:
338ff772f70Snicm case MAGIC_TYPE_UQLDATE:
339ff772f70Snicm case MAGIC_TYPE_BEQUAD:
340ff772f70Snicm case MAGIC_TYPE_UBEQUAD:
341ff772f70Snicm case MAGIC_TYPE_BEDOUBLE:
342ff772f70Snicm case MAGIC_TYPE_BEQDATE:
343ff772f70Snicm case MAGIC_TYPE_BEQLDATE:
344ff772f70Snicm case MAGIC_TYPE_UBEQDATE:
345ff772f70Snicm case MAGIC_TYPE_UBEQLDATE:
346ff772f70Snicm case MAGIC_TYPE_LEQUAD:
347ff772f70Snicm case MAGIC_TYPE_ULEQUAD:
348ff772f70Snicm case MAGIC_TYPE_LEDOUBLE:
349ff772f70Snicm case MAGIC_TYPE_LEQDATE:
350ff772f70Snicm case MAGIC_TYPE_LEQLDATE:
351ff772f70Snicm case MAGIC_TYPE_ULEQDATE:
352ff772f70Snicm case MAGIC_TYPE_ULEQLDATE:
353ff772f70Snicm case MAGIC_TYPE_LELONG:
354ff772f70Snicm case MAGIC_TYPE_ULELONG:
355ff772f70Snicm case MAGIC_TYPE_LEFLOAT:
356ff772f70Snicm case MAGIC_TYPE_LEDATE:
357ff772f70Snicm case MAGIC_TYPE_LELDATE:
358ff772f70Snicm case MAGIC_TYPE_ULEDATE:
359ff772f70Snicm case MAGIC_TYPE_ULELDATE:
360ff772f70Snicm case MAGIC_TYPE_MELONG:
361ff772f70Snicm case MAGIC_TYPE_MEDATE:
362ff772f70Snicm case MAGIC_TYPE_MELDATE:
363ff772f70Snicm n += 8 * MAGIC_STRENGTH_MULTIPLIER;
364ff772f70Snicm break;
365ff772f70Snicm case MAGIC_TYPE_STRING:
366ff772f70Snicm case MAGIC_TYPE_PSTRING:
367ff772f70Snicm n += ml->test_string_size * MAGIC_STRENGTH_MULTIPLIER;
368ff772f70Snicm break;
369ff772f70Snicm case MAGIC_TYPE_BESTRING16:
370ff772f70Snicm case MAGIC_TYPE_LESTRING16:
371ff772f70Snicm n += ml->test_string_size * MAGIC_STRENGTH_MULTIPLIER / 2;
372ff772f70Snicm break;
373ff772f70Snicm case MAGIC_TYPE_REGEX:
374ff772f70Snicm case MAGIC_TYPE_SEARCH:
375ff772f70Snicm size = MAGIC_STRENGTH_MULTIPLIER / ml->test_string_size;
376ff772f70Snicm if (size < 1)
377ff772f70Snicm size = 1;
378ff772f70Snicm n += ml->test_string_size * size;
379ff772f70Snicm break;
380ff772f70Snicm }
381ff772f70Snicm switch (ml->test_operator) {
382ff772f70Snicm case '=':
383ff772f70Snicm n += MAGIC_STRENGTH_MULTIPLIER;
384ff772f70Snicm break;
385ff772f70Snicm case '<':
386ff772f70Snicm case '>':
387ff772f70Snicm case '[':
388ff772f70Snicm case ']':
389ff772f70Snicm n -= 2 * MAGIC_STRENGTH_MULTIPLIER;
390ff772f70Snicm break;
391ff772f70Snicm case '^':
392ff772f70Snicm case '&':
393ff772f70Snicm n -= MAGIC_STRENGTH_MULTIPLIER;
394ff772f70Snicm break;
395ff772f70Snicm }
396cd410a1eSnicm
397cd410a1eSnicm skip:
398cd410a1eSnicm switch (ml->strength_operator) {
399cd410a1eSnicm case '+':
400cd410a1eSnicm n += ml->strength_value;
401cd410a1eSnicm break;
402cd410a1eSnicm case '-':
403cd410a1eSnicm n -= ml->strength_value;
404cd410a1eSnicm break;
405cd410a1eSnicm case '*':
406cd410a1eSnicm n *= ml->strength_value;
407cd410a1eSnicm break;
408cd410a1eSnicm case '/':
409cd410a1eSnicm n /= ml->strength_value;
410cd410a1eSnicm break;
411cd410a1eSnicm }
412ff772f70Snicm return (n <= 0 ? 1 : n);
413ff772f70Snicm }
414ff772f70Snicm
415ff772f70Snicm static int
magic_get_string(char ** line,char * out,size_t * outlen)416ff772f70Snicm magic_get_string(char **line, char *out, size_t *outlen)
417ff772f70Snicm {
418ff772f70Snicm char *start, *cp, c;
419ff772f70Snicm int d0, d1, d2;
420ff772f70Snicm
421ff772f70Snicm start = out;
422ff772f70Snicm for (cp = *line; *cp != '\0' && !isspace((u_char)*cp); cp++) {
423ff772f70Snicm if (*cp != '\\') {
424ff772f70Snicm *out++ = *cp;
425ff772f70Snicm continue;
426ff772f70Snicm }
427ff772f70Snicm
428ff772f70Snicm switch (c = *++cp) {
4292dae82d5Snicm case '\0': /* end of line */
4302dae82d5Snicm return (-1);
431ff772f70Snicm case ' ':
432ff772f70Snicm *out++ = ' ';
433ff772f70Snicm break;
434ff772f70Snicm case '0':
435ff772f70Snicm case '1':
436ff772f70Snicm case '2':
437ff772f70Snicm case '3':
438ff772f70Snicm case '4':
439ff772f70Snicm case '5':
440ff772f70Snicm case '6':
441ff772f70Snicm case '7':
442ff772f70Snicm d0 = magic_odigit(cp[0]);
443ff772f70Snicm if (cp[0] != '\0')
444ff772f70Snicm d1 = magic_odigit(cp[1]);
445ff772f70Snicm else
446ff772f70Snicm d1 = -1;
447ff772f70Snicm if (cp[0] != '\0' && cp[1] != '\0')
448ff772f70Snicm d2 = magic_odigit(cp[2]);
449ff772f70Snicm else
450ff772f70Snicm d2 = -1;
451ff772f70Snicm
452ff772f70Snicm if (d0 != -1 && d1 != -1 && d2 != -1) {
453ff772f70Snicm *out = d2 | (d1 << 3) | (d0 << 6);
454ff772f70Snicm cp += 2;
455ff772f70Snicm } else if (d0 != -1 && d1 != -1) {
456ff772f70Snicm *out = d1 | (d0 << 3);
457ff772f70Snicm cp++;
458ff772f70Snicm } else if (d0 != -1)
459ff772f70Snicm *out = d0;
460ff772f70Snicm else
461ff772f70Snicm return (-1);
462ff772f70Snicm out++;
463ff772f70Snicm break;
464ff772f70Snicm case 'x':
465ff772f70Snicm d0 = magic_xdigit(cp[1]);
466ff772f70Snicm if (cp[1] != '\0')
467ff772f70Snicm d1 = magic_xdigit(cp[2]);
468ff772f70Snicm else
469ff772f70Snicm d1 = -1;
470ff772f70Snicm
471ff772f70Snicm if (d0 != -1 && d1 != -1) {
472ff772f70Snicm *out = d1 | (d0 << 4);
473ff772f70Snicm cp += 2;
474ff772f70Snicm } else if (d0 != -1) {
475ff772f70Snicm *out = d0;
476ff772f70Snicm cp++;
477ff772f70Snicm } else
478ff772f70Snicm return (-1);
479ff772f70Snicm out++;
480ff772f70Snicm
481ff772f70Snicm break;
482ff772f70Snicm case 'a':
483ff772f70Snicm *out++ = '\a';
484ff772f70Snicm break;
485ff772f70Snicm case 'b':
486ff772f70Snicm *out++ = '\b';
487ff772f70Snicm break;
488ff772f70Snicm case 't':
489ff772f70Snicm *out++ = '\t';
490ff772f70Snicm break;
491ff772f70Snicm case 'f':
492ff772f70Snicm *out++ = '\f';
493ff772f70Snicm break;
494ff772f70Snicm case 'n':
495ff772f70Snicm *out++ = '\n';
496ff772f70Snicm break;
497ff772f70Snicm case 'r':
498ff772f70Snicm *out++ = '\r';
499ff772f70Snicm break;
500ff772f70Snicm case '\\':
501ff772f70Snicm *out++ = '\\';
502ff772f70Snicm break;
503ff772f70Snicm case '\'':
504ff772f70Snicm *out++ = '\'';
505ff772f70Snicm break;
506ff772f70Snicm case '\"':
507ff772f70Snicm *out++ = '\"';
508ff772f70Snicm break;
509ff772f70Snicm default:
510ff772f70Snicm *out++ = c;
511ff772f70Snicm break;
512ff772f70Snicm }
513ff772f70Snicm }
514ff772f70Snicm *out = '\0';
515ff772f70Snicm *outlen = out - start;
516ff772f70Snicm
517ff772f70Snicm *line = cp;
518ff772f70Snicm return (0);
519ff772f70Snicm }
520ff772f70Snicm
521ff772f70Snicm static int
magic_parse_offset(struct magic_line * ml,char ** line)522ff772f70Snicm magic_parse_offset(struct magic_line *ml, char **line)
523ff772f70Snicm {
524ff772f70Snicm char *copy, *s, *cp, *endptr;
525ff772f70Snicm
526ff772f70Snicm while (isspace((u_char)**line))
527ff772f70Snicm (*line)++;
528ff772f70Snicm copy = s = cp = xmalloc(strlen(*line) + 1);
529ff772f70Snicm while (**line != '\0' && !isspace((u_char)**line))
530ff772f70Snicm *cp++ = *(*line)++;
531ff772f70Snicm *cp = '\0';
532ff772f70Snicm
533ff772f70Snicm ml->offset = 0;
534ff772f70Snicm ml->offset_relative = 0;
535ff772f70Snicm
536ff772f70Snicm ml->indirect_type = ' ';
537ff772f70Snicm ml->indirect_relative = 0;
538ff772f70Snicm ml->indirect_offset = 0;
539ff772f70Snicm ml->indirect_operator = ' ';
540ff772f70Snicm ml->indirect_operand = 0;
541ff772f70Snicm
542ff772f70Snicm if (*s == '&') {
543ff772f70Snicm ml->offset_relative = 1;
544ff772f70Snicm s++;
545ff772f70Snicm }
546ff772f70Snicm
547ff772f70Snicm if (*s != '(') {
548ff772f70Snicm endptr = magic_strtoll(s, &ml->offset);
549ff772f70Snicm if (endptr == NULL || *endptr != '\0') {
550ff772f70Snicm magic_warn(ml, "missing closing bracket");
551ff772f70Snicm goto fail;
552ff772f70Snicm }
553ff772f70Snicm if (ml->offset < 0 && !ml->offset_relative) {
554ff772f70Snicm magic_warn(ml, "negative absolute offset");
555ff772f70Snicm goto fail;
556ff772f70Snicm }
557ff772f70Snicm goto done;
558ff772f70Snicm }
559ff772f70Snicm s++;
560ff772f70Snicm
561ff772f70Snicm if (*s == '&') {
562ff772f70Snicm ml->indirect_relative = 1;
563ff772f70Snicm s++;
564ff772f70Snicm }
565ff772f70Snicm
566ff772f70Snicm endptr = magic_strtoll(s, &ml->indirect_offset);
567ff772f70Snicm if (endptr == NULL) {
568987c627aSnicm magic_warn(ml, "can't parse offset: %s", s);
569ff772f70Snicm goto fail;
570ff772f70Snicm }
571ff772f70Snicm s = endptr;
572ff772f70Snicm if (*s == ')')
573ff772f70Snicm goto done;
574ff772f70Snicm
575ff772f70Snicm if (*s == '.') {
576ff772f70Snicm s++;
57777169b9dStobias if (*s == '\0' || strchr("bslBSL", *s) == NULL) {
578987c627aSnicm magic_warn(ml, "unknown offset type: %c", *s);
579ff772f70Snicm goto fail;
580ff772f70Snicm }
581ff772f70Snicm ml->indirect_type = *s;
582ff772f70Snicm s++;
583ff772f70Snicm if (*s == ')')
584ff772f70Snicm goto done;
585ff772f70Snicm }
586ff772f70Snicm
58777169b9dStobias if (*s == '\0' || strchr("+-*", *s) == NULL) {
588987c627aSnicm magic_warn(ml, "unknown offset operator: %c", *s);
589ff772f70Snicm goto fail;
590ff772f70Snicm }
591ff772f70Snicm ml->indirect_operator = *s;
592ff772f70Snicm s++;
593ff772f70Snicm if (*s == ')')
594ff772f70Snicm goto done;
595ff772f70Snicm
596ff772f70Snicm if (*s == '(') {
597ff772f70Snicm s++;
598ff772f70Snicm endptr = magic_strtoll(s, &ml->indirect_operand);
599ff772f70Snicm if (endptr == NULL || *endptr != ')') {
600ff772f70Snicm magic_warn(ml, "missing closing bracket");
601ff772f70Snicm goto fail;
602ff772f70Snicm }
603ff772f70Snicm if (*++endptr != ')') {
604ff772f70Snicm magic_warn(ml, "missing closing bracket");
605ff772f70Snicm goto fail;
606ff772f70Snicm }
607ff772f70Snicm } else {
608ff772f70Snicm endptr = magic_strtoll(s, &ml->indirect_operand);
609ff772f70Snicm if (endptr == NULL || *endptr != ')') {
610ff772f70Snicm magic_warn(ml, "missing closing bracket");
611ff772f70Snicm goto fail;
612ff772f70Snicm }
613ff772f70Snicm }
614ff772f70Snicm
615ff772f70Snicm done:
616ff772f70Snicm free(copy);
617ff772f70Snicm return (0);
618ff772f70Snicm
619ff772f70Snicm fail:
620ff772f70Snicm free(copy);
621ff772f70Snicm return (-1);
622ff772f70Snicm }
623ff772f70Snicm
624ff772f70Snicm static int
magic_parse_type(struct magic_line * ml,char ** line)625ff772f70Snicm magic_parse_type(struct magic_line *ml, char **line)
626ff772f70Snicm {
627ff772f70Snicm char *copy, *s, *cp, *endptr;
628ff772f70Snicm
629ff772f70Snicm while (isspace((u_char)**line))
630ff772f70Snicm (*line)++;
631ff772f70Snicm copy = s = cp = xmalloc(strlen(*line) + 1);
632ff772f70Snicm while (**line != '\0' && !isspace((u_char)**line))
633ff772f70Snicm *cp++ = *(*line)++;
634ff772f70Snicm *cp = '\0';
635ff772f70Snicm
636ff772f70Snicm ml->type = MAGIC_TYPE_NONE;
637ff772f70Snicm ml->type_operator = ' ';
638ff772f70Snicm ml->type_operand = 0;
639ff772f70Snicm
640e5597b92Snicm if (strcmp(s, "name") == 0) {
641c673ceb0Snicm ml->type = MAGIC_TYPE_NAME;
642c673ceb0Snicm ml->type_string = xstrdup(s);
643c673ceb0Snicm goto done;
644c673ceb0Snicm }
645e5597b92Snicm if (strcmp(s, "use") == 0) {
646c673ceb0Snicm ml->type = MAGIC_TYPE_USE;
647c673ceb0Snicm ml->type_string = xstrdup(s);
648c673ceb0Snicm goto done;
649c673ceb0Snicm }
650c673ceb0Snicm
6515df908a8Snicm if (strncmp(s, "string", (sizeof "string") - 1) == 0 ||
6525df908a8Snicm strncmp(s, "ustring", (sizeof "ustring") - 1) == 0) {
6535df908a8Snicm if (*s == 'u')
6545df908a8Snicm ml->type_string = xstrdup(s + 1);
6555df908a8Snicm else
6565df908a8Snicm ml->type_string = xstrdup(s);
657ff772f70Snicm ml->type = MAGIC_TYPE_STRING;
658ff772f70Snicm magic_mark_text(ml, 0);
659ff772f70Snicm goto done;
660ff772f70Snicm }
6615df908a8Snicm if (strncmp(s, "pstring", (sizeof "pstring") - 1) == 0 ||
6625df908a8Snicm strncmp(s, "upstring", (sizeof "upstring") - 1) == 0) {
6635df908a8Snicm if (*s == 'u')
6645df908a8Snicm ml->type_string = xstrdup(s + 1);
6655df908a8Snicm else
6665df908a8Snicm ml->type_string = xstrdup(s);
6675df908a8Snicm ml->type = MAGIC_TYPE_PSTRING;
6685df908a8Snicm magic_mark_text(ml, 0);
6695df908a8Snicm goto done;
6705df908a8Snicm }
6715df908a8Snicm if (strncmp(s, "search", (sizeof "search") - 1) == 0 ||
6725df908a8Snicm strncmp(s, "usearch", (sizeof "usearch") - 1) == 0) {
6735df908a8Snicm if (*s == 'u')
6745df908a8Snicm ml->type_string = xstrdup(s + 1);
6755df908a8Snicm else
6765df908a8Snicm ml->type_string = xstrdup(s);
677ff772f70Snicm ml->type = MAGIC_TYPE_SEARCH;
678ff772f70Snicm goto done;
679ff772f70Snicm }
6805df908a8Snicm if (strncmp(s, "regex", (sizeof "regex") - 1) == 0 ||
6815df908a8Snicm strncmp(s, "uregex", (sizeof "uregex") - 1) == 0) {
6825df908a8Snicm if (*s == 'u')
6835df908a8Snicm ml->type_string = xstrdup(s + 1);
6845df908a8Snicm else
6855df908a8Snicm ml->type_string = xstrdup(s);
686ff772f70Snicm ml->type = MAGIC_TYPE_REGEX;
687ff772f70Snicm goto done;
688ff772f70Snicm }
6895df908a8Snicm ml->type_string = xstrdup(s);
690ff772f70Snicm
6913115b575Snicm cp = &s[strcspn(s, "+-&/%*")];
692ff772f70Snicm if (*cp != '\0') {
693ff772f70Snicm ml->type_operator = *cp;
694ff772f70Snicm endptr = magic_strtoull(cp + 1, &ml->type_operand);
695ff772f70Snicm if (endptr == NULL || *endptr != '\0') {
696987c627aSnicm magic_warn(ml, "can't parse operand: %s", cp + 1);
697ff772f70Snicm goto fail;
698ff772f70Snicm }
699ff772f70Snicm *cp = '\0';
700ff772f70Snicm }
701ff772f70Snicm
702ff772f70Snicm if (strcmp(s, "byte") == 0)
703ff772f70Snicm ml->type = MAGIC_TYPE_BYTE;
704ff772f70Snicm else if (strcmp(s, "short") == 0)
705ff772f70Snicm ml->type = MAGIC_TYPE_SHORT;
706ff772f70Snicm else if (strcmp(s, "long") == 0)
707ff772f70Snicm ml->type = MAGIC_TYPE_LONG;
708ff772f70Snicm else if (strcmp(s, "quad") == 0)
709ff772f70Snicm ml->type = MAGIC_TYPE_QUAD;
710ff772f70Snicm else if (strcmp(s, "ubyte") == 0)
711ff772f70Snicm ml->type = MAGIC_TYPE_UBYTE;
712ff772f70Snicm else if (strcmp(s, "ushort") == 0)
713ff772f70Snicm ml->type = MAGIC_TYPE_USHORT;
714ff772f70Snicm else if (strcmp(s, "ulong") == 0)
715ff772f70Snicm ml->type = MAGIC_TYPE_ULONG;
716ff772f70Snicm else if (strcmp(s, "uquad") == 0)
717ff772f70Snicm ml->type = MAGIC_TYPE_UQUAD;
7185df908a8Snicm else if (strcmp(s, "float") == 0 || strcmp(s, "ufloat") == 0)
719ff772f70Snicm ml->type = MAGIC_TYPE_FLOAT;
7205df908a8Snicm else if (strcmp(s, "double") == 0 || strcmp(s, "udouble") == 0)
721ff772f70Snicm ml->type = MAGIC_TYPE_DOUBLE;
722ff772f70Snicm else if (strcmp(s, "date") == 0)
723ff772f70Snicm ml->type = MAGIC_TYPE_DATE;
724ff772f70Snicm else if (strcmp(s, "qdate") == 0)
725ff772f70Snicm ml->type = MAGIC_TYPE_QDATE;
726ff772f70Snicm else if (strcmp(s, "ldate") == 0)
727ff772f70Snicm ml->type = MAGIC_TYPE_LDATE;
728ff772f70Snicm else if (strcmp(s, "qldate") == 0)
729ff772f70Snicm ml->type = MAGIC_TYPE_QLDATE;
730ff772f70Snicm else if (strcmp(s, "udate") == 0)
731ff772f70Snicm ml->type = MAGIC_TYPE_UDATE;
732ff772f70Snicm else if (strcmp(s, "uqdate") == 0)
733ff772f70Snicm ml->type = MAGIC_TYPE_UQDATE;
734ff772f70Snicm else if (strcmp(s, "uldate") == 0)
735ff772f70Snicm ml->type = MAGIC_TYPE_ULDATE;
736ff772f70Snicm else if (strcmp(s, "uqldate") == 0)
737ff772f70Snicm ml->type = MAGIC_TYPE_UQLDATE;
738ff772f70Snicm else if (strcmp(s, "beshort") == 0)
739ff772f70Snicm ml->type = MAGIC_TYPE_BESHORT;
740ff772f70Snicm else if (strcmp(s, "belong") == 0)
741ff772f70Snicm ml->type = MAGIC_TYPE_BELONG;
742ff772f70Snicm else if (strcmp(s, "bequad") == 0)
743ff772f70Snicm ml->type = MAGIC_TYPE_BEQUAD;
744ff772f70Snicm else if (strcmp(s, "ubeshort") == 0)
745ff772f70Snicm ml->type = MAGIC_TYPE_UBESHORT;
746ff772f70Snicm else if (strcmp(s, "ubelong") == 0)
747ff772f70Snicm ml->type = MAGIC_TYPE_UBELONG;
748ff772f70Snicm else if (strcmp(s, "ubequad") == 0)
749ff772f70Snicm ml->type = MAGIC_TYPE_UBEQUAD;
7505df908a8Snicm else if (strcmp(s, "befloat") == 0 || strcmp(s, "ubefloat") == 0)
751ff772f70Snicm ml->type = MAGIC_TYPE_BEFLOAT;
7525df908a8Snicm else if (strcmp(s, "bedouble") == 0 || strcmp(s, "ubedouble") == 0)
753ff772f70Snicm ml->type = MAGIC_TYPE_BEDOUBLE;
754ff772f70Snicm else if (strcmp(s, "bedate") == 0)
755ff772f70Snicm ml->type = MAGIC_TYPE_BEDATE;
756ff772f70Snicm else if (strcmp(s, "beqdate") == 0)
757ff772f70Snicm ml->type = MAGIC_TYPE_BEQDATE;
758ff772f70Snicm else if (strcmp(s, "beldate") == 0)
759ff772f70Snicm ml->type = MAGIC_TYPE_BELDATE;
760ff772f70Snicm else if (strcmp(s, "beqldate") == 0)
761ff772f70Snicm ml->type = MAGIC_TYPE_BEQLDATE;
762ff772f70Snicm else if (strcmp(s, "ubedate") == 0)
763ff772f70Snicm ml->type = MAGIC_TYPE_UBEDATE;
764ff772f70Snicm else if (strcmp(s, "ubeqdate") == 0)
765ff772f70Snicm ml->type = MAGIC_TYPE_UBEQDATE;
766ff772f70Snicm else if (strcmp(s, "ubeldate") == 0)
767ff772f70Snicm ml->type = MAGIC_TYPE_UBELDATE;
768ff772f70Snicm else if (strcmp(s, "ubeqldate") == 0)
769ff772f70Snicm ml->type = MAGIC_TYPE_UBEQLDATE;
7705df908a8Snicm else if (strcmp(s, "bestring16") == 0 || strcmp(s, "ubestring16") == 0)
771ff772f70Snicm ml->type = MAGIC_TYPE_BESTRING16;
772ff772f70Snicm else if (strcmp(s, "leshort") == 0)
773ff772f70Snicm ml->type = MAGIC_TYPE_LESHORT;
774ff772f70Snicm else if (strcmp(s, "lelong") == 0)
775ff772f70Snicm ml->type = MAGIC_TYPE_LELONG;
776ff772f70Snicm else if (strcmp(s, "lequad") == 0)
777ff772f70Snicm ml->type = MAGIC_TYPE_LEQUAD;
778ff772f70Snicm else if (strcmp(s, "uleshort") == 0)
779ff772f70Snicm ml->type = MAGIC_TYPE_ULESHORT;
780ff772f70Snicm else if (strcmp(s, "ulelong") == 0)
781ff772f70Snicm ml->type = MAGIC_TYPE_ULELONG;
782ff772f70Snicm else if (strcmp(s, "ulequad") == 0)
783ff772f70Snicm ml->type = MAGIC_TYPE_ULEQUAD;
7845df908a8Snicm else if (strcmp(s, "lefloat") == 0 || strcmp(s, "ulefloat") == 0)
785ff772f70Snicm ml->type = MAGIC_TYPE_LEFLOAT;
7865df908a8Snicm else if (strcmp(s, "ledouble") == 0 || strcmp(s, "uledouble") == 0)
787ff772f70Snicm ml->type = MAGIC_TYPE_LEDOUBLE;
788ff772f70Snicm else if (strcmp(s, "ledate") == 0)
789ff772f70Snicm ml->type = MAGIC_TYPE_LEDATE;
790ff772f70Snicm else if (strcmp(s, "leqdate") == 0)
791ff772f70Snicm ml->type = MAGIC_TYPE_LEQDATE;
792ff772f70Snicm else if (strcmp(s, "leldate") == 0)
793ff772f70Snicm ml->type = MAGIC_TYPE_LELDATE;
794ff772f70Snicm else if (strcmp(s, "leqldate") == 0)
795ff772f70Snicm ml->type = MAGIC_TYPE_LEQLDATE;
796ff772f70Snicm else if (strcmp(s, "uledate") == 0)
797ff772f70Snicm ml->type = MAGIC_TYPE_ULEDATE;
798ff772f70Snicm else if (strcmp(s, "uleqdate") == 0)
799ff772f70Snicm ml->type = MAGIC_TYPE_ULEQDATE;
800ff772f70Snicm else if (strcmp(s, "uleldate") == 0)
801ff772f70Snicm ml->type = MAGIC_TYPE_ULELDATE;
802ff772f70Snicm else if (strcmp(s, "uleqldate") == 0)
803ff772f70Snicm ml->type = MAGIC_TYPE_ULEQLDATE;
8045df908a8Snicm else if (strcmp(s, "lestring16") == 0 || strcmp(s, "ulestring16") == 0)
805ff772f70Snicm ml->type = MAGIC_TYPE_LESTRING16;
8065df908a8Snicm else if (strcmp(s, "melong") == 0 || strcmp(s, "umelong") == 0)
807ff772f70Snicm ml->type = MAGIC_TYPE_MELONG;
8085df908a8Snicm else if (strcmp(s, "medate") == 0 || strcmp(s, "umedate") == 0)
809ff772f70Snicm ml->type = MAGIC_TYPE_MEDATE;
8105df908a8Snicm else if (strcmp(s, "meldate") == 0 || strcmp(s, "umeldate") == 0)
811ff772f70Snicm ml->type = MAGIC_TYPE_MELDATE;
8125df908a8Snicm else if (strcmp(s, "default") == 0 || strcmp(s, "udefault") == 0)
813ff772f70Snicm ml->type = MAGIC_TYPE_DEFAULT;
814e0a3e3d1Snicm else if (strcmp(s, "clear") == 0 || strcmp(s, "uclear") == 0)
815e0a3e3d1Snicm ml->type = MAGIC_TYPE_CLEAR;
816ff772f70Snicm else {
817987c627aSnicm magic_warn(ml, "unknown type: %s", s);
818ff772f70Snicm goto fail;
819ff772f70Snicm }
820ff772f70Snicm magic_mark_text(ml, 0);
821ff772f70Snicm
822ff772f70Snicm done:
823ff772f70Snicm free(copy);
824ff772f70Snicm return (0);
825ff772f70Snicm
826ff772f70Snicm fail:
827ff772f70Snicm free(copy);
828ff772f70Snicm return (-1);
829ff772f70Snicm }
830ff772f70Snicm
831ff772f70Snicm static int
magic_parse_value(struct magic_line * ml,char ** line)832ff772f70Snicm magic_parse_value(struct magic_line *ml, char **line)
833ff772f70Snicm {
834ff772f70Snicm char *copy, *s, *cp, *endptr;
835ff772f70Snicm size_t slen;
836c7e9ea26Snicm uint64_t u;
837ff772f70Snicm
838ff772f70Snicm while (isspace((u_char)**line))
839ff772f70Snicm (*line)++;
840ff772f70Snicm
841ff772f70Snicm ml->test_operator = '=';
842ff772f70Snicm ml->test_not = 0;
843ff772f70Snicm ml->test_string = NULL;
844ff772f70Snicm ml->test_string_size = 0;
845ff772f70Snicm ml->test_unsigned = 0;
846ff772f70Snicm ml->test_signed = 0;
847ff772f70Snicm
8486d6dc887Snicm if (**line == '\0')
8496d6dc887Snicm return (0);
8506d6dc887Snicm
851ff772f70Snicm s = *line;
852ff772f70Snicm if (s[0] == 'x' && (s[1] == '\0' || isspace((u_char)s[1]))) {
853ff772f70Snicm (*line)++;
854ff772f70Snicm ml->test_operator = 'x';
855ff772f70Snicm return (0);
856ff772f70Snicm }
857ff772f70Snicm
858e0a3e3d1Snicm if (ml->type == MAGIC_TYPE_DEFAULT || ml->type == MAGIC_TYPE_CLEAR) {
859e0a3e3d1Snicm magic_warn(ml, "test specified for default or clear");
860e0a3e3d1Snicm ml->test_operator = 'x';
861e0a3e3d1Snicm return (0);
862e0a3e3d1Snicm }
863e0a3e3d1Snicm
864ff772f70Snicm if (**line == '!') {
865ff772f70Snicm ml->test_not = 1;
866ff772f70Snicm (*line)++;
867ff772f70Snicm }
868ff772f70Snicm
869ff772f70Snicm switch (ml->type) {
870c673ceb0Snicm case MAGIC_TYPE_NAME:
871c673ceb0Snicm case MAGIC_TYPE_USE:
872c673ceb0Snicm copy = s = xmalloc(strlen(*line) + 1);
873c673ceb0Snicm if (magic_get_string(line, s, &slen) != 0 || slen == 0) {
874c673ceb0Snicm magic_warn(ml, "can't parse string");
875c673ceb0Snicm goto fail;
876c673ceb0Snicm }
877c673ceb0Snicm if (slen == 0 || *s == '\0' || strcmp(s, "^") == 0) {
878c673ceb0Snicm magic_warn(ml, "invalid name");
879c673ceb0Snicm goto fail;
880c673ceb0Snicm }
881c673ceb0Snicm ml->name = s;
882c673ceb0Snicm return (0); /* do not free */
883ff772f70Snicm case MAGIC_TYPE_STRING:
884ff772f70Snicm case MAGIC_TYPE_PSTRING:
885ff772f70Snicm case MAGIC_TYPE_SEARCH:
886ff772f70Snicm if (**line == '>' || **line == '<' || **line == '=') {
887ff772f70Snicm ml->test_operator = **line;
888ff772f70Snicm (*line)++;
889ff772f70Snicm }
890ff772f70Snicm /* FALLTHROUGH */
891ff772f70Snicm case MAGIC_TYPE_REGEX:
892d06473cbSnicm if (**line == '=')
893d06473cbSnicm (*line)++;
894ff772f70Snicm copy = s = xmalloc(strlen(*line) + 1);
895ff772f70Snicm if (magic_get_string(line, s, &slen) != 0) {
896ff772f70Snicm magic_warn(ml, "can't parse string");
897ff772f70Snicm goto fail;
898ff772f70Snicm }
899ff772f70Snicm ml->test_string_size = slen;
900ff772f70Snicm ml->test_string = s;
901ff772f70Snicm return (0); /* do not free */
902ff772f70Snicm default:
903ff772f70Snicm break;
904ff772f70Snicm }
905ff772f70Snicm
9066d6dc887Snicm while (isspace((u_char)**line))
9076d6dc887Snicm (*line)++;
9086d6dc887Snicm if ((*line)[0] == '<' && (*line)[1] == '=') {
9096d6dc887Snicm ml->test_operator = '[';
910ff772f70Snicm (*line) += 2;
9116d6dc887Snicm } else if ((*line)[0] == '>' && (*line)[1] == '=') {
9126d6dc887Snicm ml->test_operator = ']';
9136d6dc887Snicm (*line) += 2;
91434cca548Stobias } else if (**line != '\0' && strchr("=<>&^", **line) != NULL) {
9156d6dc887Snicm ml->test_operator = **line;
9166d6dc887Snicm (*line)++;
917ff772f70Snicm }
9186d6dc887Snicm
9196d6dc887Snicm while (isspace((u_char)**line))
9206d6dc887Snicm (*line)++;
9216d6dc887Snicm copy = cp = xmalloc(strlen(*line) + 1);
922ff772f70Snicm while (**line != '\0' && !isspace((u_char)**line))
923ff772f70Snicm *cp++ = *(*line)++;
924ff772f70Snicm *cp = '\0';
925ff772f70Snicm
92695651d73Snicm switch (ml->type) {
92795651d73Snicm case MAGIC_TYPE_FLOAT:
92895651d73Snicm case MAGIC_TYPE_DOUBLE:
92995651d73Snicm case MAGIC_TYPE_BEFLOAT:
93095651d73Snicm case MAGIC_TYPE_BEDOUBLE:
93195651d73Snicm case MAGIC_TYPE_LEFLOAT:
93295651d73Snicm case MAGIC_TYPE_LEDOUBLE:
93395651d73Snicm errno = 0;
93495651d73Snicm ml->test_double = strtod(copy, &endptr);
93595651d73Snicm if (errno == ERANGE)
93695651d73Snicm endptr = NULL;
93795651d73Snicm break;
93895651d73Snicm default:
939ff772f70Snicm if (*ml->type_string == 'u')
9406d6dc887Snicm endptr = magic_strtoull(copy, &ml->test_unsigned);
941c7e9ea26Snicm else {
9426d6dc887Snicm endptr = magic_strtoll(copy, &ml->test_signed);
943ff772f70Snicm if (endptr == NULL || *endptr != '\0') {
944c7e9ea26Snicm /*
94595651d73Snicm * If we can't parse this as a signed number,
94695651d73Snicm * try as unsigned instead.
947c7e9ea26Snicm */
948c7e9ea26Snicm endptr = magic_strtoull(copy, &u);
949c7e9ea26Snicm if (endptr != NULL && *endptr == '\0')
950c7e9ea26Snicm ml->test_signed = (int64_t)u;
951c7e9ea26Snicm }
952c7e9ea26Snicm }
95395651d73Snicm break;
95495651d73Snicm }
955c7e9ea26Snicm if (endptr == NULL || *endptr != '\0') {
9566d6dc887Snicm magic_warn(ml, "can't parse number: %s", copy);
957ff772f70Snicm goto fail;
958ff772f70Snicm }
959ff772f70Snicm
960ff772f70Snicm free(copy);
961ff772f70Snicm return (0);
962ff772f70Snicm
963ff772f70Snicm fail:
964ff772f70Snicm free(copy);
965ff772f70Snicm return (-1);
966ff772f70Snicm }
967ff772f70Snicm
968ff772f70Snicm int
magic_compare(struct magic_line * ml1,struct magic_line * ml2)969ff772f70Snicm magic_compare(struct magic_line *ml1, struct magic_line *ml2)
970ff772f70Snicm {
971ff772f70Snicm if (ml1->strength < ml2->strength)
972ff772f70Snicm return (1);
973ff772f70Snicm if (ml1->strength > ml2->strength)
974ff772f70Snicm return (-1);
975ff772f70Snicm
976ff772f70Snicm /*
977ff772f70Snicm * The original file depends on the (undefined!) qsort(3) behaviour
978ff772f70Snicm * when the strength is equal. This is impossible to reproduce with an
979ff772f70Snicm * RB tree so just use the line number and hope for the best.
980ff772f70Snicm */
981ff772f70Snicm if (ml1->line < ml2->line)
982ff772f70Snicm return (-1);
983ff772f70Snicm if (ml1->line > ml2->line)
984ff772f70Snicm return (1);
985ff772f70Snicm
986ff772f70Snicm return (0);
987ff772f70Snicm }
988ff772f70Snicm RB_GENERATE(magic_tree, magic_line, node, magic_compare);
989ff772f70Snicm
990c673ceb0Snicm int
magic_named_compare(struct magic_line * ml1,struct magic_line * ml2)991c673ceb0Snicm magic_named_compare(struct magic_line *ml1, struct magic_line *ml2)
992c673ceb0Snicm {
993c673ceb0Snicm return (strcmp(ml1->name, ml2->name));
994c673ceb0Snicm }
995c673ceb0Snicm RB_GENERATE(magic_named_tree, magic_line, node, magic_named_compare);
996c673ceb0Snicm
997ff772f70Snicm static void
magic_adjust_strength(struct magic * m,u_int at,struct magic_line * ml,char * line)998cd410a1eSnicm magic_adjust_strength(struct magic *m, u_int at, struct magic_line *ml,
999cd410a1eSnicm char *line)
1000cd410a1eSnicm {
1001cd410a1eSnicm char *cp, *s;
1002cd410a1eSnicm int64_t value;
1003cd410a1eSnicm
1004cd410a1eSnicm cp = line + (sizeof "!:strength") - 1;
1005cd410a1eSnicm while (isspace((u_char)*cp))
1006cd410a1eSnicm cp++;
1007cd410a1eSnicm s = cp;
1008cd410a1eSnicm
1009cd410a1eSnicm cp = strchr(s, '#');
1010cd410a1eSnicm if (cp != NULL)
1011cd410a1eSnicm *cp = '\0';
1012cd410a1eSnicm cp = s;
1013cd410a1eSnicm
101434cca548Stobias if (*s == '\0' || strchr("+-*/", *s) == NULL) {
1015cd410a1eSnicm magic_warnm(m, at, "invalid strength operator: %s", s);
1016cd410a1eSnicm return;
1017cd410a1eSnicm }
1018cd410a1eSnicm ml->strength_operator = *cp++;
1019cd410a1eSnicm
1020cd410a1eSnicm while (isspace((u_char)*cp))
1021cd410a1eSnicm cp++;
1022cd410a1eSnicm cp = magic_strtoll(cp, &value);
1023cd410a1eSnicm while (cp != NULL && isspace((u_char)*cp))
1024cd410a1eSnicm cp++;
1025cd410a1eSnicm if (cp == NULL || *cp != '\0' || value < 0 || value > 255) {
1026cd410a1eSnicm magic_warnm(m, at, "invalid strength value: %s", s);
1027cd410a1eSnicm return;
1028cd410a1eSnicm }
1029cd410a1eSnicm ml->strength_value = value;
1030cd410a1eSnicm }
1031cd410a1eSnicm
1032cd410a1eSnicm static void
magic_set_mimetype(struct magic * m,u_int at,struct magic_line * ml,char * line)1033ff772f70Snicm magic_set_mimetype(struct magic *m, u_int at, struct magic_line *ml, char *line)
1034ff772f70Snicm {
1035ff772f70Snicm char *mimetype, *cp;
1036ff772f70Snicm
1037ff772f70Snicm mimetype = line + (sizeof "!:mime") - 1;
1038ff772f70Snicm while (isspace((u_char)*mimetype))
1039ff772f70Snicm mimetype++;
1040ff772f70Snicm
1041ff772f70Snicm cp = strchr(mimetype, '#');
1042ff772f70Snicm if (cp != NULL)
1043ff772f70Snicm *cp = '\0';
1044ff772f70Snicm
1045ff772f70Snicm if (*mimetype != '\0') {
1046ff772f70Snicm cp = mimetype + strlen(mimetype) - 1;
1047ff772f70Snicm while (cp != mimetype && isspace((u_char)*cp))
1048ff772f70Snicm *cp-- = '\0';
1049ff772f70Snicm }
1050ff772f70Snicm
1051ff772f70Snicm cp = mimetype;
1052ff772f70Snicm while (*cp != '\0') {
1053ff772f70Snicm if (!isalnum((u_char)*cp) && strchr("/-.+", *cp) == NULL)
1054ff772f70Snicm break;
1055ff772f70Snicm cp++;
1056ff772f70Snicm }
1057ff772f70Snicm if (*mimetype == '\0' || *cp != '\0') {
10585c6c4bceSnicm magic_warnm(m, at, "invalid MIME type: %s", mimetype);
1059ff772f70Snicm return;
1060ff772f70Snicm }
1061ff772f70Snicm if (ml == NULL) {
10625c6c4bceSnicm magic_warnm(m, at, "stray MIME type: %s", mimetype);
1063ff772f70Snicm return;
1064ff772f70Snicm }
1065ff772f70Snicm ml->mimetype = xstrdup(mimetype);
1066ff772f70Snicm }
1067ff772f70Snicm
1068ff772f70Snicm struct magic *
magic_load(FILE * f,const char * path,int warnings)1069ff772f70Snicm magic_load(FILE *f, const char *path, int warnings)
1070ff772f70Snicm {
1071ff772f70Snicm struct magic *m;
1072ff772f70Snicm struct magic_line *ml = NULL, *parent, *parent0;
1073ff772f70Snicm char *line, *tmp;
1074ff772f70Snicm size_t size;
1075*de3a6565Sbrynet ssize_t slen;
1076ff772f70Snicm u_int at, level, n, i;
1077ff772f70Snicm
1078ff772f70Snicm m = xcalloc(1, sizeof *m);
1079ff772f70Snicm m->path = xstrdup(path);
1080ff772f70Snicm m->warnings = warnings;
1081ff772f70Snicm RB_INIT(&m->tree);
1082ff772f70Snicm
1083ff772f70Snicm parent = NULL;
1084ff772f70Snicm parent0 = NULL;
1085ff772f70Snicm level = 0;
1086ff772f70Snicm
1087ff772f70Snicm at = 0;
1088ff772f70Snicm tmp = NULL;
1089*de3a6565Sbrynet size = 0;
1090*de3a6565Sbrynet while ((slen = getline(&tmp, &size, f)) != -1) {
1091ff772f70Snicm line = tmp;
1092*de3a6565Sbrynet if (line[slen - 1] == '\n')
1093*de3a6565Sbrynet line[slen - 1] = '\0';
1094*de3a6565Sbrynet
1095ff772f70Snicm at++;
1096ff772f70Snicm
1097ff772f70Snicm while (isspace((u_char)*line))
1098ff772f70Snicm line++;
1099ff772f70Snicm if (*line == '\0' || *line == '#')
1100ff772f70Snicm continue;
1101ff772f70Snicm
1102d828ca33Snicm if (strncmp (line, "!:mime", 6) == 0) {
1103ff772f70Snicm magic_set_mimetype(m, at, ml, line);
1104ff772f70Snicm continue;
1105ff772f70Snicm }
1106cd410a1eSnicm if (strncmp (line, "!:strength", 10) == 0) {
1107cd410a1eSnicm magic_adjust_strength(m, at, ml, line);
1108cd410a1eSnicm continue;
1109cd410a1eSnicm }
1110d828ca33Snicm if (strncmp (line, "!:", 2) == 0) {
1111d828ca33Snicm for (i = 0; i < 64 && line[i] != '\0'; i++) {
1112d828ca33Snicm if (isspace((u_char)line[i]))
1113d828ca33Snicm break;
1114d828ca33Snicm }
1115d828ca33Snicm magic_warnm(m, at, "%.*s not supported", i, line);
1116d828ca33Snicm continue;
1117d828ca33Snicm }
1118ff772f70Snicm
1119ff772f70Snicm n = 0;
1120ff772f70Snicm for (; *line == '>'; line++)
1121ff772f70Snicm n++;
1122ff772f70Snicm
1123ff772f70Snicm ml = xcalloc(1, sizeof *ml);
1124ff772f70Snicm ml->root = m;
1125ff772f70Snicm ml->line = at;
1126ff772f70Snicm ml->type = MAGIC_TYPE_NONE;
1127ff772f70Snicm TAILQ_INIT(&ml->children);
1128ff772f70Snicm ml->text = 1;
1129ff772f70Snicm
1130853bdbd5Snicm /*
1131853bdbd5Snicm * At this point n is the level we want, level is the current
1132853bdbd5Snicm * level. parent0 is the last line at the same level and parent
1133853bdbd5Snicm * is the last line at the previous level.
1134853bdbd5Snicm */
1135ff772f70Snicm if (n == level + 1) {
1136ff772f70Snicm parent = parent0;
1137ff772f70Snicm } else if (n < level) {
1138ff772f70Snicm for (i = n; i < level && parent != NULL; i++)
1139ff772f70Snicm parent = parent->parent;
1140ff772f70Snicm } else if (n != level) {
1141ff772f70Snicm magic_warn(ml, "level skipped (%u->%u)", level, n);
1142ff772f70Snicm free(ml);
1143ff772f70Snicm continue;
1144ff772f70Snicm }
1145ff772f70Snicm ml->parent = parent;
1146ff772f70Snicm level = n;
1147ff772f70Snicm
1148ff772f70Snicm if (magic_parse_offset(ml, &line) != 0 ||
1149ff772f70Snicm magic_parse_type(ml, &line) != 0 ||
1150ff772f70Snicm magic_parse_value(ml, &line) != 0 ||
1151ff772f70Snicm magic_set_result(ml, line) != 0) {
1152853bdbd5Snicm /*
1153853bdbd5Snicm * An invalid line still needs to appear in the tree in
1154853bdbd5Snicm * case it has any children.
1155853bdbd5Snicm */
1156853bdbd5Snicm ml->type = MAGIC_TYPE_NONE;
1157ff772f70Snicm }
1158ff772f70Snicm
1159ff772f70Snicm ml->strength = magic_get_strength(ml);
1160c673ceb0Snicm if (ml->parent == NULL) {
1161c673ceb0Snicm if (ml->name != NULL)
1162c673ceb0Snicm RB_INSERT(magic_named_tree, &m->named, ml);
1163ff772f70Snicm else
1164c673ceb0Snicm RB_INSERT(magic_tree, &m->tree, ml);
1165c673ceb0Snicm } else
1166ff772f70Snicm TAILQ_INSERT_TAIL(&ml->parent->children, ml, entry);
1167ff772f70Snicm parent0 = ml;
1168ff772f70Snicm }
1169ff772f70Snicm free(tmp);
1170*de3a6565Sbrynet if (ferror(f))
1171*de3a6565Sbrynet err(1, "%s", path);
1172ff772f70Snicm
1173ff772f70Snicm return (m);
1174ff772f70Snicm }
1175