Upgrade to file-5.03.
[games.git] / contrib / file / src / apprentice.c
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  * apprentice - make one pass through /etc/magic, learning its secrets.
30  */
31
32 #include "file.h"
33
34 #ifndef lint
35 FILE_RCSID("@(#)$File: apprentice.c,v 1.151 2009/03/18 15:19:23 christos Exp $")
36 #endif  /* lint */
37
38 #include "magic.h"
39 #include "patchlevel.h"
40 #include <stdlib.h>
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #include <string.h>
45 #include <assert.h>
46 #include <ctype.h>
47 #include <fcntl.h>
48 #ifdef QUICK
49 #include <sys/mman.h>
50 #endif
51 #include <dirent.h>
52
53 #define EATAB {while (isascii((unsigned char) *l) && \
54                       isspace((unsigned char) *l))  ++l;}
55 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
56                         tolower((unsigned char) (l)) : (l))
57 /*
58  * Work around a bug in headers on Digital Unix.
59  * At least confirmed for: OSF1 V4.0 878
60  */
61 #if defined(__osf__) && defined(__DECC)
62 #ifdef MAP_FAILED
63 #undef MAP_FAILED
64 #endif
65 #endif
66
67 #ifndef MAP_FAILED
68 #define MAP_FAILED (void *) -1
69 #endif
70
71 #ifndef MAP_FILE
72 #define MAP_FILE 0
73 #endif
74
75 #ifndef MAXPATHLEN
76 #define MAXPATHLEN      1024
77 #endif
78
79 struct magic_entry {
80         struct magic *mp;       
81         uint32_t cont_count;
82         uint32_t max_count;
83 };
84
85 int file_formats[FILE_NAMES_SIZE];
86 const size_t file_nformats = FILE_NAMES_SIZE;
87 const char *file_names[FILE_NAMES_SIZE];
88 const size_t file_nnames = FILE_NAMES_SIZE;
89
90 private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
91 private int hextoint(int);
92 private const char *getstr(struct magic_set *, struct magic *, const char *,
93     int);
94 private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
95     const char *, size_t, int);
96 private void eatsize(const char **);
97 private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
98 private size_t apprentice_magic_strength(const struct magic *);
99 private int apprentice_sort(const void *, const void *);
100 private int apprentice_load(struct magic_set *, struct magic **, uint32_t *,
101     const char *, int);
102 private void byteswap(struct magic *, uint32_t);
103 private void bs1(struct magic *);
104 private uint16_t swap2(uint16_t);
105 private uint32_t swap4(uint32_t);
106 private uint64_t swap8(uint64_t);
107 private char *mkdbname(struct magic_set *, const char *, int);
108 private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
109     const char *);
110 private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
111     const char *);
112 private int check_format_type(const char *, int);
113 private int check_format(struct magic_set *, struct magic *);
114 private int get_op(char);
115 private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
116 private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
117 private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
118
119
120 private size_t maxmagic = 0;
121 private size_t magicsize = sizeof(struct magic);
122
123 private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
124
125 private struct {
126         const char *name;
127         size_t len;
128         int (*fun)(struct magic_set *, struct magic_entry *, const char *);
129 } bang[] = {
130 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
131         DECLARE_FIELD(mime),
132         DECLARE_FIELD(apple),
133         DECLARE_FIELD(strength),
134 #undef  DECLARE_FIELD
135         { NULL, 0, NULL }
136 };
137
138 #ifdef COMPILE_ONLY
139
140 int main(int, char *[]);
141
142 int
143 main(int argc, char *argv[])
144 {
145         int ret;
146         struct magic_set *ms;
147         char *progname;
148
149         if ((progname = strrchr(argv[0], '/')) != NULL)
150                 progname++;
151         else
152                 progname = argv[0];
153
154         if (argc != 2) {
155                 (void)fprintf(stderr, "Usage: %s file\n", progname);
156                 return 1;
157         }
158
159         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
160                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
161                 return 1;
162         }
163         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
164         if (ret == 1)
165                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
166         magic_close(ms);
167         return ret;
168 }
169 #endif /* COMPILE_ONLY */
170
171 static const struct type_tbl_s {
172         const char name[16];
173         const size_t len;
174         const int type;
175         const int format;
176 } type_tbl[] = {
177 # define XX(s)          s, (sizeof(s) - 1)
178 # define XX_NULL        "", 0
179         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
180         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
181         { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
182         { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
183         { XX("string"),         FILE_STRING,            FILE_FMT_STR },
184         { XX("date"),           FILE_DATE,              FILE_FMT_STR },
185         { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
186         { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
187         { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
188         { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
189         { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
190         { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
191         { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
192         { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
193         { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
194         { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
195         { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
196         { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
197         { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
198         { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
199         { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
200         { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
201         { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
202         { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
203         { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
204         { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
205         { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
206         { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
207         { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
208         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
209         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
210         { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
211         { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
212         { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
213         { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
214         { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
215         { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
216         { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
217         { XX("leid3"),          FILE_LEID3,             FILE_FMT_NUM },
218         { XX("beid3"),          FILE_BEID3,             FILE_FMT_NUM },
219         { XX("indirect"),       FILE_INDIRECT,          FILE_FMT_NONE },
220         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
221 # undef XX
222 # undef XX_NULL
223 };
224
225 private int
226 get_type(const char *l, const char **t)
227 {
228         const struct type_tbl_s *p;
229
230         for (p = type_tbl; p->len; p++) {
231                 if (strncmp(l, p->name, p->len) == 0) {
232                         if (t)
233                                 *t = l + p->len;
234                         break;
235                 }
236         }
237         return p->type;
238 }
239
240 private void
241 init_file_tables(void)
242 {
243         static int done = 0;
244         const struct type_tbl_s *p;
245
246         if (done)
247                 return;
248         done++;
249
250         for (p = type_tbl; p->len; p++) {
251                 assert(p->type < FILE_NAMES_SIZE);
252                 file_names[p->type] = p->name;
253                 file_formats[p->type] = p->format;
254         }
255 }
256
257 /*
258  * Handle one file or directory.
259  */
260 private int
261 apprentice_1(struct magic_set *ms, const char *fn, int action,
262     struct mlist *mlist)
263 {
264         struct magic *magic = NULL;
265         uint32_t nmagic = 0;
266         struct mlist *ml;
267         int rv = -1;
268         int mapped;
269
270         if (magicsize != FILE_MAGICSIZE) {
271                 file_error(ms, 0, "magic element size %lu != %lu",
272                     (unsigned long)sizeof(*magic),
273                     (unsigned long)FILE_MAGICSIZE);
274                 return -1;
275         }
276
277         if (action == FILE_COMPILE) {
278                 rv = apprentice_load(ms, &magic, &nmagic, fn, action);
279                 if (rv != 0)
280                         return -1;
281                 rv = apprentice_compile(ms, &magic, &nmagic, fn);
282                 free(magic);
283                 return rv;
284         }
285
286 #ifndef COMPILE_ONLY
287         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
288                 if (ms->flags & MAGIC_CHECK)
289                         file_magwarn(ms, "using regular magic file `%s'", fn);
290                 rv = apprentice_load(ms, &magic, &nmagic, fn, action);
291                 if (rv != 0)
292                         return -1;
293         }
294
295         mapped = rv;
296              
297         if (magic == NULL) {
298                 file_delmagic(magic, mapped, nmagic);
299                 return -1;
300         }
301
302         if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) {
303                 file_delmagic(magic, mapped, nmagic);
304                 file_oomem(ms, sizeof(*ml));
305                 return -1;
306         }
307
308         ml->magic = magic;
309         ml->nmagic = nmagic;
310         ml->mapped = mapped;
311
312         mlist->prev->next = ml;
313         ml->prev = mlist->prev;
314         ml->next = mlist;
315         mlist->prev = ml;
316
317         return 0;
318 #endif /* COMPILE_ONLY */
319 }
320
321 protected void
322 file_delmagic(struct magic *p, int type, size_t entries)
323 {
324         if (p == NULL)
325                 return;
326         switch (type) {
327         case 2:
328 #ifdef QUICK
329                 p--;
330                 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
331                 break;
332 #else
333                 (void)&entries;
334                 abort();
335                 /*NOTREACHED*/
336 #endif
337         case 1:
338                 p--;
339                 /*FALLTHROUGH*/
340         case 0:
341                 free(p);
342                 break;
343         default:
344                 abort();
345         }
346 }
347
348 /* const char *fn: list of magic files and directories */
349 protected struct mlist *
350 file_apprentice(struct magic_set *ms, const char *fn, int action)
351 {
352         char *p, *mfn;
353         int file_err, errs = -1;
354         struct mlist *mlist;
355
356         init_file_tables();
357
358         if (fn == NULL)
359                 fn = getenv("MAGIC");
360         if (fn == NULL)
361                 fn = MAGIC;
362
363         if ((mfn = strdup(fn)) == NULL) {
364                 file_oomem(ms, strlen(fn));
365                 return NULL;
366         }
367         fn = mfn;
368
369         if ((mlist = CAST(struct mlist *, malloc(sizeof(*mlist)))) == NULL) {
370                 free(mfn);
371                 file_oomem(ms, sizeof(*mlist));
372                 return NULL;
373         }
374         mlist->next = mlist->prev = mlist;
375
376         while (fn) {
377                 p = strchr(fn, PATHSEP);
378                 if (p)
379                         *p++ = '\0';
380                 if (*fn == '\0')
381                         break;
382                 file_err = apprentice_1(ms, fn, action, mlist);
383                 errs = MAX(errs, file_err);
384                 fn = p;
385         }
386         if (errs == -1) {
387                 free(mfn);
388                 free(mlist);
389                 mlist = NULL;
390                 file_error(ms, 0, "could not find any magic files!");
391                 return NULL;
392         }
393         free(mfn);
394         return mlist;
395 }
396
397 /*
398  * Get weight of this magic entry, for sorting purposes.
399  */
400 private size_t
401 apprentice_magic_strength(const struct magic *m)
402 {
403 #define MULT 10
404         size_t val = 2 * MULT;  /* baseline strength */
405
406         switch (m->type) {
407         case FILE_DEFAULT:      /* make sure this sorts last */
408                 if (m->factor_op != FILE_FACTOR_OP_NONE)
409                         abort();
410                 return 0;
411
412         case FILE_BYTE:
413                 val += 1 * MULT;
414                 break;
415
416         case FILE_SHORT:
417         case FILE_LESHORT:
418         case FILE_BESHORT:
419                 val += 2 * MULT;
420                 break;
421
422         case FILE_LONG:
423         case FILE_LELONG:
424         case FILE_BELONG:
425         case FILE_MELONG:
426                 val += 4 * MULT;
427                 break;
428
429         case FILE_PSTRING:
430         case FILE_STRING:
431                 val += m->vallen * MULT;
432                 break;
433
434         case FILE_BESTRING16:
435         case FILE_LESTRING16:
436                 val += m->vallen * MULT / 2;
437                 break;
438
439         case FILE_SEARCH:
440         case FILE_REGEX:
441                 val += m->vallen * MAX(MULT / m->vallen, 1);
442                 break;
443
444         case FILE_DATE:
445         case FILE_LEDATE:
446         case FILE_BEDATE:
447         case FILE_MEDATE:
448         case FILE_LDATE:
449         case FILE_LELDATE:
450         case FILE_BELDATE:
451         case FILE_MELDATE:
452         case FILE_FLOAT:
453         case FILE_BEFLOAT:
454         case FILE_LEFLOAT:
455                 val += 4 * MULT;
456                 break;
457
458         case FILE_QUAD:
459         case FILE_BEQUAD:
460         case FILE_LEQUAD:
461         case FILE_QDATE:
462         case FILE_LEQDATE:
463         case FILE_BEQDATE:
464         case FILE_QLDATE:
465         case FILE_LEQLDATE:
466         case FILE_BEQLDATE:
467         case FILE_DOUBLE:
468         case FILE_BEDOUBLE:
469         case FILE_LEDOUBLE:
470                 val += 8 * MULT;
471                 break;
472
473         default:
474                 val = 0;
475                 (void)fprintf(stderr, "Bad type %d\n", m->type);
476                 abort();
477         }
478
479         switch (m->reln) {
480         case 'x':       /* matches anything penalize */
481         case '!':       /* matches almost anything penalize */
482                 val = 0;
483                 break;
484
485         case '=':       /* Exact match, prefer */
486                 val += MULT;
487                 break;
488
489         case '>':
490         case '<':       /* comparison match reduce strength */
491                 val -= 2 * MULT;
492                 break;
493
494         case '^':
495         case '&':       /* masking bits, we could count them too */
496                 val -= MULT;
497                 break;
498
499         default:
500                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
501                 abort();
502         }
503
504         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
505                 val = 1;
506
507         switch (m->factor_op) {
508         case FILE_FACTOR_OP_NONE:
509                 break;
510         case FILE_FACTOR_OP_PLUS:
511                 val += m->factor;
512                 break;
513         case FILE_FACTOR_OP_MINUS:
514                 val -= m->factor;
515                 break;
516         case FILE_FACTOR_OP_TIMES:
517                 val *= m->factor;
518                 break;
519         case FILE_FACTOR_OP_DIV:
520                 val /= m->factor;
521                 break;
522         default:
523                 abort();
524         }
525
526         /*
527          * Magic entries with no description get a bonus because they depend
528          * on subsequent magic entries to print something.
529          */
530         if (m->desc[0] == '\0')
531                 val++;
532         return val;
533 }
534
535 /*  
536  * Sort callback for sorting entries by "strength" (basically length)
537  */
538 private int
539 apprentice_sort(const void *a, const void *b)
540 {
541         const struct magic_entry *ma = CAST(const struct magic_entry *, a);
542         const struct magic_entry *mb = CAST(const struct magic_entry *, b);
543         size_t sa = apprentice_magic_strength(ma->mp);
544         size_t sb = apprentice_magic_strength(mb->mp);
545         if (sa == sb)
546                 return 0;
547         else if (sa > sb)
548                 return -1;
549         else
550                 return 1;
551 }
552
553 private void
554 set_test_type(struct magic *mstart, struct magic *m)
555 {
556         switch (m->type) {
557         case FILE_BYTE:
558         case FILE_SHORT:
559         case FILE_LONG:
560         case FILE_DATE:
561         case FILE_BESHORT:
562         case FILE_BELONG:
563         case FILE_BEDATE:
564         case FILE_LESHORT:
565         case FILE_LELONG:
566         case FILE_LEDATE:
567         case FILE_LDATE:
568         case FILE_BELDATE:
569         case FILE_LELDATE:
570         case FILE_MEDATE:
571         case FILE_MELDATE:
572         case FILE_MELONG:
573         case FILE_QUAD:
574         case FILE_LEQUAD:
575         case FILE_BEQUAD:
576         case FILE_QDATE:
577         case FILE_LEQDATE:
578         case FILE_BEQDATE:
579         case FILE_QLDATE:
580         case FILE_LEQLDATE:
581         case FILE_BEQLDATE:
582         case FILE_FLOAT:
583         case FILE_BEFLOAT:
584         case FILE_LEFLOAT:
585         case FILE_DOUBLE:
586         case FILE_BEDOUBLE:
587         case FILE_LEDOUBLE:
588         case FILE_STRING:
589         case FILE_PSTRING:
590         case FILE_BESTRING16:
591         case FILE_LESTRING16:
592                 /* binary test, set flag */
593                 mstart->flag |= BINTEST;
594                 break;
595         case FILE_REGEX:
596         case FILE_SEARCH:
597                 /* binary test if pattern is not text */
598                 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
599                     NULL) <= 0)
600                         mstart->flag |= BINTEST;
601                 break;
602         case FILE_DEFAULT:
603                 /* can't deduce anything; we shouldn't see this at the
604                    top level anyway */
605                 break;
606         case FILE_INVALID:
607         default:
608                 /* invalid search type, but no need to complain here */
609                 break;
610         }
611 }
612
613 /*
614  * Load and parse one file.
615  */
616 private void
617 load_1(struct magic_set *ms, int action, const char *fn, int *errs,
618    struct magic_entry **marray, uint32_t *marraycount)
619 {
620         char line[BUFSIZ];
621         size_t lineno = 0;
622         FILE *f = fopen(ms->file = fn, "r");
623         if (f == NULL) {
624                 if (errno != ENOENT)
625                         file_error(ms, errno, "cannot read magic file `%s'",
626                                    fn);
627                 (*errs)++;
628         } else {
629                 /* read and parse this file */
630                 for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
631                         size_t len;
632                         len = strlen(line);
633                         if (len == 0) /* null line, garbage, etc */
634                                 continue;
635                         if (line[len - 1] == '\n') {
636                                 lineno++;
637                                 line[len - 1] = '\0'; /* delete newline */
638                         }
639                         if (line[0] == '\0')    /* empty, do not parse */
640                                 continue;
641                         if (line[0] == '#')     /* comment, do not parse */
642                                 continue;
643                         if (line[0] == '!' && line[1] == ':') {
644                                 size_t i;
645
646                                 for (i = 0; bang[i].name != NULL; i++) {
647                                         if (len - 2 > bang[i].len &&
648                                             memcmp(bang[i].name, line + 2,
649                                             bang[i].len) == 0)
650                                                 break;
651                                 }
652                                 if (bang[i].name == NULL) {
653                                         file_error(ms, 0,
654                                             "Unknown !: entry `%s'", line);
655                                         (*errs)++;
656                                         continue;
657                                 }
658                                 if (*marraycount == 0) {
659                                         file_error(ms, 0,
660                                             "No current entry for :!%s type",
661                                                 bang[i].name);
662                                         (*errs)++;
663                                         continue;
664                                 }
665                                 if ((*bang[i].fun)(ms, 
666                                     &(*marray)[*marraycount - 1],
667                                     line + bang[i].len + 2) != 0) {
668                                         (*errs)++;
669                                         continue;
670                                 }
671                                 continue;
672                         }
673                         if (parse(ms, marray, marraycount, line, lineno,
674                             action) != 0)
675                                 (*errs)++;
676                 }
677
678                 (void)fclose(f);
679         }
680 }
681
682 /*
683  * parse a file or directory of files
684  * const char *fn: name of magic file or directory
685  */
686 private int
687 apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
688     const char *fn, int action)
689 {
690         int errs = 0;
691         struct magic_entry *marray;
692         uint32_t marraycount, i, mentrycount = 0, starttest;
693         size_t slen;
694         char subfn[MAXPATHLEN];
695         struct stat st;
696         DIR *dir;
697         struct dirent *d;
698
699         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
700
701         maxmagic = MAXMAGIS;
702         if ((marray = CAST(struct magic_entry *, calloc(maxmagic,
703             sizeof(*marray)))) == NULL) {
704                 file_oomem(ms, maxmagic * sizeof(*marray));
705                 return -1;
706         }
707         marraycount = 0;
708
709         /* print silly verbose header for USG compat. */
710         if (action == FILE_CHECK)
711                 (void)fprintf(stderr, "%s\n", usg_hdr);
712
713         /* load directory or file */
714         /* FIXME: Read file names and sort them to prevent
715            non-determinism. See Debian bug #488562. */
716         if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
717                 dir = opendir(fn);
718                 if (dir) {
719                         while ((d = readdir(dir)) != NULL) {
720                                 snprintf(subfn, sizeof(subfn), "%s/%s",
721                                     fn, d->d_name);
722                                 if (stat(subfn, &st) == 0 &&
723                                     S_ISREG(st.st_mode)) {
724                                         load_1(ms, action, subfn, &errs,
725                                             &marray, &marraycount);
726                                 }
727                         }
728                         closedir(dir);
729                 } else
730                         errs++;
731         } else
732                 load_1(ms, action, fn, &errs, &marray, &marraycount);
733         if (errs)
734                 goto out;
735
736         /* Set types of tests */
737         for (i = 0; i < marraycount; ) {
738                 if (marray[i].mp->cont_level != 0) {
739                         i++;
740                         continue;
741                 }
742
743                 starttest = i;
744                 do {
745                         static const char text[] = "text";
746                         static const char binary[] = "binary";
747                         static const size_t len = sizeof(text);
748                         set_test_type(marray[starttest].mp, marray[i].mp);
749                         if ((ms->flags & MAGIC_DEBUG) == 0)
750                                 continue;
751                         (void)fprintf(stderr, "%s%s%s: %s\n",
752                             marray[i].mp->mimetype,
753                             marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
754                             marray[i].mp->desc[0] ? marray[i].mp->desc :
755                             "(no description)",
756                             marray[i].mp->flag & BINTEST ? binary : text);
757                         if (marray[i].mp->flag & BINTEST) {
758                                 char *p = strstr(marray[i].mp->desc, text);
759                                 if (p && (p == marray[i].mp->desc ||
760                                     isspace((unsigned char)p[-1])) &&
761                                     (p + len - marray[i].mp->desc == 
762                                     MAXstring || (p[len] == '\0' ||
763                                     isspace((unsigned char)p[len]))))
764                                         (void)fprintf(stderr, "*** Possible "
765                                             "binary test for text type\n");
766                         }
767                 } while (++i < marraycount && marray[i].mp->cont_level != 0);
768         }
769
770         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
771
772         /*
773          * Make sure that any level 0 "default" line is last (if one exists).
774          */
775         for (i = 0; i < marraycount; i++) {
776                 if (marray[i].mp->cont_level == 0 &&
777                     marray[i].mp->type == FILE_DEFAULT) {
778                         while (++i < marraycount)
779                                 if (marray[i].mp->cont_level == 0)
780                                         break;
781                         if (i != marraycount) {
782                                 ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
783                                 file_magwarn(ms,
784                                     "level 0 \"default\" did not sort last");
785                         }
786                         break;                                      
787                 }
788         }
789
790         for (i = 0; i < marraycount; i++)
791                 mentrycount += marray[i].cont_count;
792
793         slen = sizeof(**magicp) * mentrycount;
794         if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) {
795                 file_oomem(ms, slen);
796                 errs++;
797                 goto out;
798         }
799
800         mentrycount = 0;
801         for (i = 0; i < marraycount; i++) {
802                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
803                     marray[i].cont_count * sizeof(**magicp));
804                 mentrycount += marray[i].cont_count;
805         }
806 out:
807         for (i = 0; i < marraycount; i++)
808                 free(marray[i].mp);
809         free(marray);
810         if (errs) {
811                 *magicp = NULL;
812                 *nmagicp = 0;
813                 return errs;
814         } else {
815                 *nmagicp = mentrycount;
816                 return 0;
817         }
818
819 }
820
821 /*
822  * extend the sign bit if the comparison is to be signed
823  */
824 protected uint64_t
825 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
826 {
827         if (!(m->flag & UNSIGNED)) {
828                 switch(m->type) {
829                 /*
830                  * Do not remove the casts below.  They are
831                  * vital.  When later compared with the data,
832                  * the sign extension must have happened.
833                  */
834                 case FILE_BYTE:
835                         v = (char) v;
836                         break;
837                 case FILE_SHORT:
838                 case FILE_BESHORT:
839                 case FILE_LESHORT:
840                         v = (short) v;
841                         break;
842                 case FILE_DATE:
843                 case FILE_BEDATE:
844                 case FILE_LEDATE:
845                 case FILE_MEDATE:
846                 case FILE_LDATE:
847                 case FILE_BELDATE:
848                 case FILE_LELDATE:
849                 case FILE_MELDATE:
850                 case FILE_LONG:
851                 case FILE_BELONG:
852                 case FILE_LELONG:
853                 case FILE_MELONG:
854                 case FILE_FLOAT:
855                 case FILE_BEFLOAT:
856                 case FILE_LEFLOAT:
857                         v = (int32_t) v;
858                         break;
859                 case FILE_QUAD:
860                 case FILE_BEQUAD:
861                 case FILE_LEQUAD:
862                 case FILE_QDATE:
863                 case FILE_QLDATE:
864                 case FILE_BEQDATE:
865                 case FILE_BEQLDATE:
866                 case FILE_LEQDATE:
867                 case FILE_LEQLDATE:
868                 case FILE_DOUBLE:
869                 case FILE_BEDOUBLE:
870                 case FILE_LEDOUBLE:
871                         v = (int64_t) v;
872                         break;
873                 case FILE_STRING:
874                 case FILE_PSTRING:
875                 case FILE_BESTRING16:
876                 case FILE_LESTRING16:
877                 case FILE_REGEX:
878                 case FILE_SEARCH:
879                 case FILE_DEFAULT:
880                 case FILE_INDIRECT:
881                         break;
882                 default:
883                         if (ms->flags & MAGIC_CHECK)
884                             file_magwarn(ms, "cannot happen: m->type=%d\n",
885                                     m->type);
886                         return ~0U;
887                 }
888         }
889         return v;
890 }
891
892 private int
893 string_modifier_check(struct magic_set *ms, struct magic *m)
894 {
895         if ((ms->flags & MAGIC_CHECK) == 0)
896                 return 0;
897
898         switch (m->type) {
899         case FILE_BESTRING16:
900         case FILE_LESTRING16:
901                 if (m->str_flags != 0) {
902                         file_magwarn(ms,
903                             "no modifiers allowed for 16-bit strings\n");
904                         return -1;
905                 }
906                 break;
907         case FILE_STRING:
908         case FILE_PSTRING:
909                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
910                         file_magwarn(ms,
911                             "'/%c' only allowed on regex and search\n",
912                             CHAR_REGEX_OFFSET_START);
913                         return -1;
914                 }
915                 break;
916         case FILE_SEARCH:
917                 if (m->str_range == 0) {
918                         file_magwarn(ms,
919                             "missing range; defaulting to %d\n",
920                             STRING_DEFAULT_RANGE);
921                         m->str_range = STRING_DEFAULT_RANGE;
922                         return -1;
923                 }
924                 break;
925         case FILE_REGEX:
926                 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
927                         file_magwarn(ms, "'/%c' not allowed on regex\n",
928                             CHAR_COMPACT_BLANK);
929                         return -1;
930                 }
931                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
932                         file_magwarn(ms, "'/%c' not allowed on regex\n",
933                             CHAR_COMPACT_OPTIONAL_BLANK);
934                         return -1;
935                 }
936                 break;
937         default:
938                 file_magwarn(ms, "coding error: m->type=%d\n",
939                     m->type);
940                 return -1;
941         }
942         return 0;
943 }
944
945 private int
946 get_op(char c)
947 {
948         switch (c) {
949         case '&':
950                 return FILE_OPAND;
951         case '|':
952                 return FILE_OPOR;
953         case '^':
954                 return FILE_OPXOR;
955         case '+':
956                 return FILE_OPADD;
957         case '-':
958                 return FILE_OPMINUS;
959         case '*':
960                 return FILE_OPMULTIPLY;
961         case '/':
962                 return FILE_OPDIVIDE;
963         case '%':
964                 return FILE_OPMODULO;
965         default:
966                 return -1;
967         }
968 }
969
970 #ifdef ENABLE_CONDITIONALS
971 private int
972 get_cond(const char *l, const char **t)
973 {
974         static const struct cond_tbl_s {
975                 char name[8];
976                 size_t len;
977                 int cond;
978         } cond_tbl[] = {
979                 { "if",         2,      COND_IF },
980                 { "elif",       4,      COND_ELIF },
981                 { "else",       4,      COND_ELSE },
982                 { "",           0,      COND_NONE },
983         };
984         const struct cond_tbl_s *p;
985
986         for (p = cond_tbl; p->len; p++) {
987                 if (strncmp(l, p->name, p->len) == 0 &&
988                     isspace((unsigned char)l[p->len])) {
989                         if (t)
990                                 *t = l + p->len;
991                         break;
992                 }
993         }
994         return p->cond;
995 }
996
997 private int
998 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
999 {
1000         int last_cond;
1001         last_cond = ms->c.li[cont_level].last_cond;
1002
1003         switch (cond) {
1004         case COND_IF:
1005                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1006                         if (ms->flags & MAGIC_CHECK)
1007                                 file_magwarn(ms, "syntax error: `if'");
1008                         return -1;
1009                 }
1010                 last_cond = COND_IF;
1011                 break;
1012
1013         case COND_ELIF:
1014                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1015                         if (ms->flags & MAGIC_CHECK)
1016                                 file_magwarn(ms, "syntax error: `elif'");
1017                         return -1;
1018                 }
1019                 last_cond = COND_ELIF;
1020                 break;
1021
1022         case COND_ELSE:
1023                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1024                         if (ms->flags & MAGIC_CHECK)
1025                                 file_magwarn(ms, "syntax error: `else'");
1026                         return -1;
1027                 }
1028                 last_cond = COND_NONE;
1029                 break;
1030
1031         case COND_NONE:
1032                 last_cond = COND_NONE;
1033                 break;
1034         }
1035
1036         ms->c.li[cont_level].last_cond = last_cond;
1037         return 0;
1038 }
1039 #endif /* ENABLE_CONDITIONALS */
1040
1041 /*
1042  * parse one line from magic file, put into magic[index++] if valid
1043  */
1044 private int
1045 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
1046     const char *line, size_t lineno, int action)
1047 {
1048 #ifdef ENABLE_CONDITIONALS
1049         static uint32_t last_cont_level = 0;
1050 #endif
1051         size_t i;
1052         struct magic_entry *me;
1053         struct magic *m;
1054         const char *l = line;
1055         char *t;
1056         int op;
1057         uint32_t cont_level;
1058
1059         cont_level = 0;
1060
1061         while (*l == '>') {
1062                 ++l;            /* step over */
1063                 cont_level++; 
1064         }
1065 #ifdef ENABLE_CONDITIONALS
1066         if (cont_level == 0 || cont_level > last_cont_level)
1067                 if (file_check_mem(ms, cont_level) == -1)
1068                         return -1;
1069         last_cont_level = cont_level;
1070 #endif
1071
1072 #define ALLOC_CHUNK     (size_t)10
1073 #define ALLOC_INCR      (size_t)200
1074
1075         if (cont_level != 0) {
1076                 if (*nmentryp == 0) {
1077                         file_error(ms, 0, "No current entry for continuation");
1078                         return -1;
1079                 }
1080                 me = &(*mentryp)[*nmentryp - 1];
1081                 if (me->cont_count == me->max_count) {
1082                         struct magic *nm;
1083                         size_t cnt = me->max_count + ALLOC_CHUNK;
1084                         if ((nm = CAST(struct magic *, realloc(me->mp,
1085                             sizeof(*nm) * cnt))) == NULL) {
1086                                 file_oomem(ms, sizeof(*nm) * cnt);
1087                                 return -1;
1088                         }
1089                         me->mp = m = nm;
1090                         me->max_count = cnt;
1091                 }
1092                 m = &me->mp[me->cont_count++];
1093                 (void)memset(m, 0, sizeof(*m));
1094                 m->cont_level = cont_level;
1095         } else {
1096                 if (*nmentryp == maxmagic) {
1097                         struct magic_entry *mp;
1098
1099                         maxmagic += ALLOC_INCR;
1100                         if ((mp = CAST(struct magic_entry *,
1101                             realloc(*mentryp, sizeof(*mp) * maxmagic))) ==
1102                             NULL) {
1103                                 file_oomem(ms, sizeof(*mp) * maxmagic);
1104                                 return -1;
1105                         }
1106                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
1107                             ALLOC_INCR);
1108                         *mentryp = mp;
1109                 }
1110                 me = &(*mentryp)[*nmentryp];
1111                 if (me->mp == NULL) {
1112                         size_t len = sizeof(*m) * ALLOC_CHUNK;
1113                         if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1114                                 file_oomem(ms, len);
1115                                 return -1;
1116                         }
1117                         me->mp = m;
1118                         me->max_count = ALLOC_CHUNK;
1119                 } else
1120                         m = me->mp;
1121                 (void)memset(m, 0, sizeof(*m));
1122                 m->factor_op = FILE_FACTOR_OP_NONE;
1123                 m->cont_level = 0;
1124                 me->cont_count = 1;
1125         }
1126         m->lineno = lineno;
1127
1128         if (*l == '&') {  /* m->cont_level == 0 checked below. */
1129                 ++l;            /* step over */
1130                 m->flag |= OFFADD;
1131         }
1132         if (*l == '(') {
1133                 ++l;            /* step over */
1134                 m->flag |= INDIR;
1135                 if (m->flag & OFFADD)
1136                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1137
1138                 if (*l == '&') {  /* m->cont_level == 0 checked below */
1139                         ++l;            /* step over */
1140                         m->flag |= OFFADD;
1141                 }
1142         }
1143         /* Indirect offsets are not valid at level 0. */
1144         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1145                 if (ms->flags & MAGIC_CHECK)
1146                         file_magwarn(ms, "relative offset at level 0");
1147
1148         /* get offset, then skip over it */
1149         m->offset = (uint32_t)strtoul(l, &t, 0);
1150         if (l == t)
1151                 if (ms->flags & MAGIC_CHECK)
1152                         file_magwarn(ms, "offset `%s' invalid", l);
1153         l = t;
1154
1155         if (m->flag & INDIR) {
1156                 m->in_type = FILE_LONG;
1157                 m->in_offset = 0;
1158                 /*
1159                  * read [.lbs][+-]nnnnn)
1160                  */
1161                 if (*l == '.') {
1162                         l++;
1163                         switch (*l) {
1164                         case 'l':
1165                                 m->in_type = FILE_LELONG;
1166                                 break;
1167                         case 'L':
1168                                 m->in_type = FILE_BELONG;
1169                                 break;
1170                         case 'm':
1171                                 m->in_type = FILE_MELONG;
1172                                 break;
1173                         case 'h':
1174                         case 's':
1175                                 m->in_type = FILE_LESHORT;
1176                                 break;
1177                         case 'H':
1178                         case 'S':
1179                                 m->in_type = FILE_BESHORT;
1180                                 break;
1181                         case 'c':
1182                         case 'b':
1183                         case 'C':
1184                         case 'B':
1185                                 m->in_type = FILE_BYTE;
1186                                 break;
1187                         case 'e':
1188                         case 'f':
1189                         case 'g':
1190                                 m->in_type = FILE_LEDOUBLE;
1191                                 break;
1192                         case 'E':
1193                         case 'F':
1194                         case 'G':
1195                                 m->in_type = FILE_BEDOUBLE;
1196                                 break;
1197                         case 'i':
1198                                 m->in_type = FILE_LEID3;
1199                                 break;
1200                         case 'I':
1201                                 m->in_type = FILE_BEID3;
1202                                 break;
1203                         default:
1204                                 if (ms->flags & MAGIC_CHECK)
1205                                         file_magwarn(ms,
1206                                             "indirect offset type `%c' invalid",
1207                                             *l);
1208                                 break;
1209                         }
1210                         l++;
1211                 }
1212
1213                 m->in_op = 0;
1214                 if (*l == '~') {
1215                         m->in_op |= FILE_OPINVERSE;
1216                         l++;
1217                 }
1218                 if ((op = get_op(*l)) != -1) {
1219                         m->in_op |= op;
1220                         l++;
1221                 }
1222                 if (*l == '(') {
1223                         m->in_op |= FILE_OPINDIRECT;
1224                         l++;
1225                 }
1226                 if (isdigit((unsigned char)*l) || *l == '-') {
1227                         m->in_offset = (int32_t)strtol(l, &t, 0);
1228                         if (l == t)
1229                                 if (ms->flags & MAGIC_CHECK)
1230                                         file_magwarn(ms,
1231                                             "in_offset `%s' invalid", l);
1232                         l = t;
1233                 }
1234                 if (*l++ != ')' || 
1235                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1236                         if (ms->flags & MAGIC_CHECK)
1237                                 file_magwarn(ms,
1238                                     "missing ')' in indirect offset");
1239         }
1240         EATAB;
1241
1242 #ifdef ENABLE_CONDITIONALS
1243         m->cond = get_cond(l, &l);
1244         if (check_cond(ms, m->cond, cont_level) == -1)
1245                 return -1;
1246
1247         EATAB;
1248 #endif
1249
1250         if (*l == 'u') {
1251                 ++l;
1252                 m->flag |= UNSIGNED;
1253         }
1254
1255         m->type = get_type(l, &l);
1256         if (m->type == FILE_INVALID) {
1257                 if (ms->flags & MAGIC_CHECK)
1258                         file_magwarn(ms, "type `%s' invalid", l);
1259                 return -1;
1260         }
1261
1262         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1263         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1264
1265         m->mask_op = 0;
1266         if (*l == '~') {
1267                 if (!IS_STRING(m->type))
1268                         m->mask_op |= FILE_OPINVERSE;
1269                 else if (ms->flags & MAGIC_CHECK)
1270                         file_magwarn(ms, "'~' invalid for string types");
1271                 ++l;
1272         }
1273         m->str_range = 0;
1274         m->str_flags = 0;
1275         m->num_mask = 0;
1276         if ((op = get_op(*l)) != -1) {
1277                 if (!IS_STRING(m->type)) {
1278                         uint64_t val;
1279                         ++l;
1280                         m->mask_op |= op;
1281                         val = (uint64_t)strtoull(l, &t, 0);
1282                         l = t;
1283                         m->num_mask = file_signextend(ms, m, val);
1284                         eatsize(&l);
1285                 }
1286                 else if (op == FILE_OPDIVIDE) {
1287                         int have_range = 0;
1288                         while (!isspace((unsigned char)*++l)) {
1289                                 switch (*l) {
1290                                 case '0':  case '1':  case '2':
1291                                 case '3':  case '4':  case '5':
1292                                 case '6':  case '7':  case '8':
1293                                 case '9':
1294                                         if (have_range &&
1295                                             (ms->flags & MAGIC_CHECK))
1296                                                 file_magwarn(ms,
1297                                                     "multiple ranges");
1298                                         have_range = 1;
1299                                         m->str_range = strtoul(l, &t, 0);
1300                                         if (m->str_range == 0)
1301                                                 file_magwarn(ms,
1302                                                     "zero range");
1303                                         l = t - 1;
1304                                         break;
1305                                 case CHAR_COMPACT_BLANK:
1306                                         m->str_flags |= STRING_COMPACT_BLANK;
1307                                         break;
1308                                 case CHAR_COMPACT_OPTIONAL_BLANK:
1309                                         m->str_flags |=
1310                                             STRING_COMPACT_OPTIONAL_BLANK;
1311                                         break;
1312                                 case CHAR_IGNORE_LOWERCASE:
1313                                         m->str_flags |= STRING_IGNORE_LOWERCASE;
1314                                         break;
1315                                 case CHAR_IGNORE_UPPERCASE:
1316                                         m->str_flags |= STRING_IGNORE_UPPERCASE;
1317                                         break;
1318                                 case CHAR_REGEX_OFFSET_START:
1319                                         m->str_flags |= REGEX_OFFSET_START;
1320                                         break;
1321                                 default:
1322                                         if (ms->flags & MAGIC_CHECK)
1323                                                 file_magwarn(ms,
1324                                                 "string extension `%c' invalid",
1325                                                 *l);
1326                                         return -1;
1327                                 }
1328                                 /* allow multiple '/' for readability */
1329                                 if (l[1] == '/' &&
1330                                     !isspace((unsigned char)l[2]))
1331                                         l++;
1332                         }
1333                         if (string_modifier_check(ms, m) == -1)
1334                                 return -1;
1335                 }
1336                 else {
1337                         if (ms->flags & MAGIC_CHECK)
1338                                 file_magwarn(ms, "invalid string op: %c", *t);
1339                         return -1;
1340                 }
1341         }
1342         /*
1343          * We used to set mask to all 1's here, instead let's just not do
1344          * anything if mask = 0 (unless you have a better idea)
1345          */
1346         EATAB;
1347   
1348         switch (*l) {
1349         case '>':
1350         case '<':
1351                 m->reln = *l;
1352                 ++l;
1353                 if (*l == '=') {
1354                         if (ms->flags & MAGIC_CHECK) {
1355                                 file_magwarn(ms, "%c= not supported",
1356                                     m->reln);
1357                                 return -1;
1358                         }
1359                    ++l;
1360                 }
1361                 break;
1362         /* Old-style anding: "0 byte &0x80 dynamically linked" */
1363         case '&':
1364         case '^':
1365         case '=':
1366                 m->reln = *l;
1367                 ++l;
1368                 if (*l == '=') {
1369                    /* HP compat: ignore &= etc. */
1370                    ++l;
1371                 }
1372                 break;
1373         case '!':
1374                 m->reln = *l;
1375                 ++l;
1376                 break;
1377         default:
1378                 m->reln = '=';  /* the default relation */
1379                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
1380                     isspace((unsigned char)l[1])) || !l[1])) {
1381                         m->reln = *l;
1382                         ++l;
1383                 }
1384                 break;
1385         }
1386         /*
1387          * Grab the value part, except for an 'x' reln.
1388          */
1389         if (m->reln != 'x' && getvalue(ms, m, &l, action))
1390                 return -1;
1391
1392         /*
1393          * TODO finish this macro and start using it!
1394          * #define offsetcheck {if (offset > HOWMANY-1) 
1395          *      magwarn("offset too big"); }
1396          */
1397
1398         /*
1399          * Now get last part - the description
1400          */
1401         EATAB;
1402         if (l[0] == '\b') {
1403                 ++l;
1404                 m->flag |= NOSPACE;
1405         } else if ((l[0] == '\\') && (l[1] == 'b')) {
1406                 ++l;
1407                 ++l;
1408                 m->flag |= NOSPACE;
1409         }
1410         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1411                 continue;
1412         if (i == sizeof(m->desc)) {
1413                 m->desc[sizeof(m->desc) - 1] = '\0';
1414                 if (ms->flags & MAGIC_CHECK)
1415                         file_magwarn(ms, "description `%s' truncated", m->desc);
1416         }
1417
1418         /*
1419          * We only do this check while compiling, or if any of the magic
1420          * files were not compiled.
1421          */
1422         if (ms->flags & MAGIC_CHECK) {
1423                 if (check_format(ms, m) == -1)
1424                         return -1;
1425         }
1426 #ifndef COMPILE_ONLY
1427         if (action == FILE_CHECK) {
1428                 file_mdump(m);
1429         }
1430 #endif
1431         m->mimetype[0] = '\0';          /* initialise MIME type to none */
1432         if (m->cont_level == 0)
1433                 ++(*nmentryp);          /* make room for next */
1434         return 0;
1435 }
1436
1437 /*
1438  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
1439  * if valid
1440  */
1441 private int
1442 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
1443 {
1444         const char *l = line;
1445         char *el;
1446         unsigned long factor;
1447         struct magic *m = &me->mp[0];
1448
1449         if (m->factor_op != FILE_FACTOR_OP_NONE) {
1450                 file_magwarn(ms,
1451                     "Current entry already has a strength type: %c %d",
1452                     m->factor_op, m->factor);
1453                 return -1;
1454         }
1455         EATAB;
1456         switch (*l) {
1457         case FILE_FACTOR_OP_NONE:
1458         case FILE_FACTOR_OP_PLUS:
1459         case FILE_FACTOR_OP_MINUS:
1460         case FILE_FACTOR_OP_TIMES:
1461         case FILE_FACTOR_OP_DIV:
1462                 m->factor_op = *l++;
1463                 break;
1464         default:
1465                 file_magwarn(ms, "Unknown factor op `%c'", *l);
1466                 return -1;
1467         }
1468         EATAB;
1469         factor = strtoul(l, &el, 0);
1470         if (factor > 255) {
1471                 file_magwarn(ms, "Too large factor `%lu'", factor);
1472                 goto out;
1473         }
1474         if (*el && !isspace((unsigned char)*el)) {
1475                 file_magwarn(ms, "Bad factor `%s'", l);
1476                 goto out;
1477         }
1478         m->factor = (uint8_t)factor;
1479         if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
1480                 file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
1481                     m->factor_op, m->factor);
1482                 goto out;
1483         }
1484         return 0;
1485 out:
1486         m->factor_op = FILE_FACTOR_OP_NONE;
1487         m->factor = 0;
1488         return -1;
1489 }
1490
1491 /*
1492  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
1493  */
1494 private int
1495 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
1496 {
1497         size_t i;
1498         const char *l = line;
1499         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1500
1501         if (m->apple[0] != '\0') {
1502                 file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
1503                     " new type `%s'", m->mimetype, l);
1504                 return -1;
1505         }       
1506
1507         EATAB;
1508         for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1509              || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
1510                 continue;
1511         if (i == sizeof(m->apple) && *l) {
1512                 if (ms->flags & MAGIC_CHECK)
1513                         file_magwarn(ms, "APPLE type `%s' truncated %zu",
1514                             line, i);
1515         }
1516
1517         if (i > 0)
1518                 return 0;
1519         else
1520                 return -1;
1521 }
1522
1523 /*
1524  * parse a MIME annotation line from magic file, put into magic[index - 1]
1525  * if valid
1526  */
1527 private int
1528 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
1529 {
1530         size_t i;
1531         const char *l = line;
1532         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1533
1534         if (m->mimetype[0] != '\0') {
1535                 file_magwarn(ms, "Current entry already has a MIME type `%s',"
1536                     " new type `%s'", m->mimetype, l);
1537                 return -1;
1538         }       
1539
1540         EATAB;
1541         for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1542              || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
1543                 continue;
1544         if (i == sizeof(m->mimetype)) {
1545                 m->desc[sizeof(m->mimetype) - 1] = '\0';
1546                 if (ms->flags & MAGIC_CHECK)
1547                         file_magwarn(ms, "MIME type `%s' truncated %zu",
1548                             m->mimetype, i);
1549         } else
1550                 m->mimetype[i] = '\0';
1551
1552         if (i > 0)
1553                 return 0;
1554         else
1555                 return -1;
1556 }
1557
1558 private int
1559 check_format_type(const char *ptr, int type)
1560 {
1561         int quad = 0;
1562         if (*ptr == '\0') {
1563                 /* Missing format string; bad */
1564                 return -1;
1565         }
1566
1567         switch (type) {
1568         case FILE_FMT_QUAD:
1569                 quad = 1;
1570                 /*FALLTHROUGH*/
1571         case FILE_FMT_NUM:
1572                 if (*ptr == '-')
1573                         ptr++;
1574                 if (*ptr == '.')
1575                         ptr++;
1576                 while (isdigit((unsigned char)*ptr)) ptr++;
1577                 if (*ptr == '.')
1578                         ptr++;
1579                 while (isdigit((unsigned char)*ptr)) ptr++;
1580                 if (quad) {
1581                         if (*ptr++ != 'l')
1582                                 return -1;
1583                         if (*ptr++ != 'l')
1584                                 return -1;
1585                 }
1586         
1587                 switch (*ptr++) {
1588                 case 'l':
1589                         switch (*ptr++) {
1590                         case 'i':
1591                         case 'd':
1592                         case 'u':
1593                         case 'x':
1594                         case 'X':
1595                                 return 0;
1596                         default:
1597                                 return -1;
1598                         }
1599                 
1600                 case 'h':
1601                         switch (*ptr++) {
1602                         case 'h':
1603                                 switch (*ptr++) {
1604                                 case 'i':
1605                                 case 'd':
1606                                 case 'u':
1607                                 case 'x':
1608                                 case 'X':
1609                                         return 0;
1610                                 default:
1611                                         return -1;
1612                                 }
1613                         case 'd':
1614                                 return 0;
1615                         default:
1616                                 return -1;
1617                         }
1618
1619                 case 'i':
1620                 case 'c':
1621                 case 'd':
1622                 case 'u':
1623                 case 'x':
1624                 case 'X':
1625                         return 0;
1626                         
1627                 default:
1628                         return -1;
1629                 }
1630                 
1631         case FILE_FMT_FLOAT:
1632         case FILE_FMT_DOUBLE:
1633                 if (*ptr == '-')
1634                         ptr++;
1635                 if (*ptr == '.')
1636                         ptr++;
1637                 while (isdigit((unsigned char)*ptr)) ptr++;
1638                 if (*ptr == '.')
1639                         ptr++;
1640                 while (isdigit((unsigned char)*ptr)) ptr++;
1641         
1642                 switch (*ptr++) {
1643                 case 'e':
1644                 case 'E':
1645                 case 'f':
1646                 case 'F':
1647                 case 'g':
1648                 case 'G':
1649                         return 0;
1650                         
1651                 default:
1652                         return -1;
1653                 }
1654                 
1655
1656         case FILE_FMT_STR:
1657                 if (*ptr == '-')
1658                         ptr++;
1659                 while (isdigit((unsigned char )*ptr))
1660                         ptr++;
1661                 if (*ptr == '.') {
1662                         ptr++;
1663                         while (isdigit((unsigned char )*ptr))
1664                                 ptr++;
1665                 }
1666                 
1667                 switch (*ptr++) {
1668                 case 's':
1669                         return 0;
1670                 default:
1671                         return -1;
1672                 }
1673                 
1674         default:
1675                 /* internal error */
1676                 abort();
1677         }
1678         /*NOTREACHED*/
1679         return -1;
1680 }
1681         
1682 /*
1683  * Check that the optional printf format in description matches
1684  * the type of the magic.
1685  */
1686 private int
1687 check_format(struct magic_set *ms, struct magic *m)
1688 {
1689         char *ptr;
1690
1691         for (ptr = m->desc; *ptr; ptr++)
1692                 if (*ptr == '%')
1693                         break;
1694         if (*ptr == '\0') {
1695                 /* No format string; ok */
1696                 return 1;
1697         }
1698
1699         assert(file_nformats == file_nnames);
1700
1701         if (m->type >= file_nformats) {
1702                 file_magwarn(ms, "Internal error inconsistency between "
1703                     "m->type and format strings");              
1704                 return -1;
1705         }
1706         if (file_formats[m->type] == FILE_FMT_NONE) {
1707                 file_magwarn(ms, "No format string for `%s' with description "
1708                     "`%s'", m->desc, file_names[m->type]);
1709                 return -1;
1710         }
1711
1712         ptr++;
1713         if (check_format_type(ptr, file_formats[m->type]) == -1) {
1714                 /*
1715                  * TODO: this error message is unhelpful if the format
1716                  * string is not one character long
1717                  */
1718                 file_magwarn(ms, "Printf format `%c' is not valid for type "
1719                     "`%s' in description `%s'", *ptr ? *ptr : '?',
1720                     file_names[m->type], m->desc);
1721                 return -1;
1722         }
1723         
1724         for (; *ptr; ptr++) {
1725                 if (*ptr == '%') {
1726                         file_magwarn(ms,
1727                             "Too many format strings (should have at most one) "
1728                             "for `%s' with description `%s'",
1729                             file_names[m->type], m->desc);
1730                         return -1;
1731                 }
1732         }
1733         return 0;
1734 }
1735
1736 /* 
1737  * Read a numeric value from a pointer, into the value union of a magic 
1738  * pointer, according to the magic type.  Update the string pointer to point 
1739  * just after the number read.  Return 0 for success, non-zero for failure.
1740  */
1741 private int
1742 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1743 {
1744         switch (m->type) {
1745         case FILE_BESTRING16:
1746         case FILE_LESTRING16:
1747         case FILE_STRING:
1748         case FILE_PSTRING:
1749         case FILE_REGEX:
1750         case FILE_SEARCH:
1751                 *p = getstr(ms, m, *p, action == FILE_COMPILE);
1752                 if (*p == NULL) {
1753                         if (ms->flags & MAGIC_CHECK)
1754                                 file_magwarn(ms, "cannot get string from `%s'",
1755                                     m->value.s);
1756                         return -1;
1757                 }
1758                 return 0;
1759         case FILE_FLOAT:
1760         case FILE_BEFLOAT:
1761         case FILE_LEFLOAT:
1762                 if (m->reln != 'x') {
1763                         char *ep;
1764 #ifdef HAVE_STRTOF
1765                         m->value.f = strtof(*p, &ep);
1766 #else
1767                         m->value.f = (float)strtod(*p, &ep);
1768 #endif
1769                         *p = ep;
1770                 }
1771                 return 0;
1772         case FILE_DOUBLE:
1773         case FILE_BEDOUBLE:
1774         case FILE_LEDOUBLE:
1775                 if (m->reln != 'x') {
1776                         char *ep;
1777                         m->value.d = strtod(*p, &ep);
1778                         *p = ep;
1779                 }
1780                 return 0;
1781         default:
1782                 if (m->reln != 'x') {
1783                         char *ep;
1784                         m->value.q = file_signextend(ms, m,
1785                             (uint64_t)strtoull(*p, &ep, 0));
1786                         *p = ep;
1787                         eatsize(p);
1788                 }
1789                 return 0;
1790         }
1791 }
1792
1793 /*
1794  * Convert a string containing C character escapes.  Stop at an unescaped
1795  * space or tab.
1796  * Copy the converted version to "m->value.s", and the length in m->vallen.
1797  * Return updated scan pointer as function result. Warn if set.
1798  */
1799 private const char *
1800 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
1801 {
1802         const char *origs = s;
1803         char    *p = m->value.s;
1804         size_t  plen = sizeof(m->value.s);
1805         char    *origp = p;
1806         char    *pmax = p + plen - 1;
1807         int     c;
1808         int     val;
1809
1810         while ((c = *s++) != '\0') {
1811                 if (isspace((unsigned char) c))
1812                         break;
1813                 if (p >= pmax) {
1814                         file_error(ms, 0, "string too long: `%s'", origs);
1815                         return NULL;
1816                 }
1817                 if (c == '\\') {
1818                         switch(c = *s++) {
1819
1820                         case '\0':
1821                                 if (warn)
1822                                         file_magwarn(ms, "incomplete escape");
1823                                 goto out;
1824
1825                         case '\t':
1826                                 if (warn) {
1827                                         file_magwarn(ms,
1828                                             "escaped tab found, use \\t instead");
1829                                         warn = 0;       /* already did */
1830                                 }
1831                                 /*FALLTHROUGH*/
1832                         default:
1833                                 if (warn) {
1834                                         if (isprint((unsigned char)c)) {
1835                                                 /* Allow escaping of 
1836                                                  * ``relations'' */
1837                                                 if (strchr("<>&^=!", c)
1838                                                     == NULL) {
1839                                                         file_magwarn(ms, "no "
1840                                                             "need to escape "
1841                                                             "`%c'", c);
1842                                                 }
1843                                         } else {
1844                                                 file_magwarn(ms,
1845                                                     "unknown escape sequence: "
1846                                                     "\\%03o", c);
1847                                         }
1848                                 }
1849                                 /*FALLTHROUGH*/
1850                         /* space, perhaps force people to use \040? */
1851                         case ' ':
1852 #if 0
1853                         /*
1854                          * Other things people escape, but shouldn't need to,
1855                          * so we disallow them
1856                          */
1857                         case '\'':
1858                         case '"':
1859                         case '?':
1860 #endif
1861                         /* Relations */
1862                         case '>':
1863                         case '<':
1864                         case '&':
1865                         case '^':
1866                         case '=':
1867                         case '!':
1868                         /* and baskslash itself */
1869                         case '\\':
1870                                 *p++ = (char) c;
1871                                 break;
1872
1873                         case 'a':
1874                                 *p++ = '\a';
1875                                 break;
1876
1877                         case 'b':
1878                                 *p++ = '\b';
1879                                 break;
1880
1881                         case 'f':
1882                                 *p++ = '\f';
1883                                 break;
1884
1885                         case 'n':
1886                                 *p++ = '\n';
1887                                 break;
1888
1889                         case 'r':
1890                                 *p++ = '\r';
1891                                 break;
1892
1893                         case 't':
1894                                 *p++ = '\t';
1895                                 break;
1896
1897                         case 'v':
1898                                 *p++ = '\v';
1899                                 break;
1900
1901                         /* \ and up to 3 octal digits */
1902                         case '0':
1903                         case '1':
1904                         case '2':
1905                         case '3':
1906                         case '4':
1907                         case '5':
1908                         case '6':
1909                         case '7':
1910                                 val = c - '0';
1911                                 c = *s++;  /* try for 2 */
1912                                 if (c >= '0' && c <= '7') {
1913                                         val = (val << 3) | (c - '0');
1914                                         c = *s++;  /* try for 3 */
1915                                         if (c >= '0' && c <= '7')
1916                                                 val = (val << 3) | (c-'0');
1917                                         else
1918                                                 --s;
1919                                 }
1920                                 else
1921                                         --s;
1922                                 *p++ = (char)val;
1923                                 break;
1924
1925                         /* \x and up to 2 hex digits */
1926                         case 'x':
1927                                 val = 'x';      /* Default if no digits */
1928                                 c = hextoint(*s++);     /* Get next char */
1929                                 if (c >= 0) {
1930                                         val = c;
1931                                         c = hextoint(*s++);
1932                                         if (c >= 0)
1933                                                 val = (val << 4) + c;
1934                                         else
1935                                                 --s;
1936                                 } else
1937                                         --s;
1938                                 *p++ = (char)val;
1939                                 break;
1940                         }
1941                 } else
1942                         *p++ = (char)c;
1943         }
1944 out:
1945         *p = '\0';
1946         m->vallen = p - origp;
1947         if (m->type == FILE_PSTRING)
1948                 m->vallen++;
1949         return s;
1950 }
1951
1952
1953 /* Single hex char to int; -1 if not a hex char. */
1954 private int
1955 hextoint(int c)
1956 {
1957         if (!isascii((unsigned char) c))
1958                 return -1;
1959         if (isdigit((unsigned char) c))
1960                 return c - '0';
1961         if ((c >= 'a') && (c <= 'f'))
1962                 return c + 10 - 'a';
1963         if (( c>= 'A') && (c <= 'F'))
1964                 return c + 10 - 'A';
1965         return -1;
1966 }
1967
1968
1969 /*
1970  * Print a string containing C character escapes.
1971  */
1972 protected void
1973 file_showstr(FILE *fp, const char *s, size_t len)
1974 {
1975         char    c;
1976
1977         for (;;) {
1978                 c = *s++;
1979                 if (len == ~0U) {
1980                         if (c == '\0')
1981                                 break;
1982                 }
1983                 else  {
1984                         if (len-- == 0)
1985                                 break;
1986                 }
1987                 if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
1988                         (void) fputc(c, fp);
1989                 else {
1990                         (void) fputc('\\', fp);
1991                         switch (c) {
1992                         case '\a':
1993                                 (void) fputc('a', fp);
1994                                 break;
1995
1996                         case '\b':
1997                                 (void) fputc('b', fp);
1998                                 break;
1999
2000                         case '\f':
2001                                 (void) fputc('f', fp);
2002                                 break;
2003
2004                         case '\n':
2005                                 (void) fputc('n', fp);
2006                                 break;
2007
2008                         case '\r':
2009                                 (void) fputc('r', fp);
2010                                 break;
2011
2012                         case '\t':
2013                                 (void) fputc('t', fp);
2014                                 break;
2015
2016                         case '\v':
2017                                 (void) fputc('v', fp);
2018                                 break;
2019
2020                         default:
2021                                 (void) fprintf(fp, "%.3o", c & 0377);
2022                                 break;
2023                         }
2024                 }
2025         }
2026 }
2027
2028 /*
2029  * eatsize(): Eat the size spec from a number [eg. 10UL]
2030  */
2031 private void
2032 eatsize(const char **p)
2033 {
2034         const char *l = *p;
2035
2036         if (LOWCASE(*l) == 'u') 
2037                 l++;
2038
2039         switch (LOWCASE(*l)) {
2040         case 'l':    /* long */
2041         case 's':    /* short */
2042         case 'h':    /* short */
2043         case 'b':    /* char/byte */
2044         case 'c':    /* char/byte */
2045                 l++;
2046                 /*FALLTHROUGH*/
2047         default:
2048                 break;
2049         }
2050
2051         *p = l;
2052 }
2053
2054 /*
2055  * handle a compiled file.
2056  */
2057 private int
2058 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
2059     const char *fn)
2060 {
2061         int fd;
2062         struct stat st;
2063         uint32_t *ptr;
2064         uint32_t version;
2065         int needsbyteswap;
2066         char *dbname = NULL;
2067         void *mm = NULL;
2068
2069         dbname = mkdbname(ms, fn, 0);
2070         if (dbname == NULL)
2071                 goto error2;
2072
2073         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2074                 goto error2;
2075
2076         if (fstat(fd, &st) == -1) {
2077                 file_error(ms, errno, "cannot stat `%s'", dbname);
2078                 goto error1;
2079         }
2080         if (st.st_size < 8) {
2081                 file_error(ms, 0, "file `%s' is too small", dbname);
2082                 goto error1;
2083         }
2084
2085 #ifdef QUICK
2086         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2087             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2088                 file_error(ms, errno, "cannot map `%s'", dbname);
2089                 goto error1;
2090         }
2091 #define RET     2
2092 #else
2093         if ((mm = CAST(void *, malloc((size_t)st.st_size))) == NULL) {
2094                 file_oomem(ms, (size_t)st.st_size);
2095                 goto error1;
2096         }
2097         if (read(fd, mm, (size_t)st.st_size) != (ssize_t)st.st_size) {
2098                 file_badread(ms);
2099                 goto error1;
2100         }
2101 #define RET     1
2102 #endif
2103         *magicp = CAST(struct magic *, mm);
2104         (void)close(fd);
2105         fd = -1;
2106         ptr = (uint32_t *)(void *)*magicp;
2107         if (*ptr != MAGICNO) {
2108                 if (swap4(*ptr) != MAGICNO) {
2109                         file_error(ms, 0, "bad magic in `%s'", dbname);
2110                         goto error1;
2111                 }
2112                 needsbyteswap = 1;
2113         } else
2114                 needsbyteswap = 0;
2115         if (needsbyteswap)
2116                 version = swap4(ptr[1]);
2117         else
2118                 version = ptr[1];
2119         if (version != VERSIONNO) {
2120                 file_error(ms, 0, "File %d.%d supports only version %d magic "
2121                     "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
2122                     VERSIONNO, dbname, version);
2123                 goto error1;
2124         }
2125         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
2126         if (*nmagicp > 0)
2127                 (*nmagicp)--;
2128         (*magicp)++;
2129         if (needsbyteswap)
2130                 byteswap(*magicp, *nmagicp);
2131         free(dbname);
2132         return RET;
2133
2134 error1:
2135         if (fd != -1)
2136                 (void)close(fd);
2137         if (mm) {
2138 #ifdef QUICK
2139                 (void)munmap((void *)mm, (size_t)st.st_size);
2140 #else
2141                 free(mm);
2142 #endif
2143         } else {
2144                 *magicp = NULL;
2145                 *nmagicp = 0;
2146         }
2147 error2:
2148         free(dbname);
2149         return -1;
2150 }
2151
2152 private const uint32_t ar[] = {
2153     MAGICNO, VERSIONNO
2154 };
2155 /*
2156  * handle an mmaped file.
2157  */
2158 private int
2159 apprentice_compile(struct magic_set *ms, struct magic **magicp,
2160     uint32_t *nmagicp, const char *fn)
2161 {
2162         int fd;
2163         char *dbname;
2164         int rv = -1;
2165
2166         dbname = mkdbname(ms, fn, 1);
2167
2168         if (dbname == NULL) 
2169                 goto out;
2170
2171         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
2172                 file_error(ms, errno, "cannot open `%s'", dbname);
2173                 goto out;
2174         }
2175
2176         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
2177                 file_error(ms, errno, "error writing `%s'", dbname);
2178                 goto out;
2179         }
2180
2181         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
2182             != sizeof(struct magic)) {
2183                 file_error(ms, errno, "error seeking `%s'", dbname);
2184                 goto out;
2185         }
2186
2187         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
2188             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
2189                 file_error(ms, errno, "error writing `%s'", dbname);
2190                 goto out;
2191         }
2192
2193         (void)close(fd);
2194         rv = 0;
2195 out:
2196         free(dbname);
2197         return rv;
2198 }
2199
2200 private const char ext[] = ".mgc";
2201 /*
2202  * make a dbname
2203  */
2204 private char *
2205 mkdbname(struct magic_set *ms, const char *fn, int strip)
2206 {
2207         const char *p, *q;
2208         char *buf;
2209
2210         if (strip) {
2211                 if ((p = strrchr(fn, '/')) != NULL)
2212                         fn = ++p;
2213         }
2214
2215         for (q = fn; *q; q++)
2216                 continue;
2217         /* Look for .mgc */
2218         for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
2219                 if (*p != *q)
2220                         break;
2221
2222         /* Did not find .mgc, restore q */
2223         if (p >= ext)
2224                 while (*q)
2225                         q++;
2226
2227         q++;
2228         /* Compatibility with old code that looked in .mime */
2229         if (ms->flags & MAGIC_MIME) {
2230                 asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext);
2231                 if (access(buf, R_OK) != -1) {
2232                         ms->flags &= MAGIC_MIME_TYPE;
2233                         return buf;
2234                 }
2235                 free(buf);
2236         }
2237         asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext);
2238
2239         /* Compatibility with old code that looked in .mime */
2240         if (strstr(p, ".mime") != NULL)
2241                 ms->flags &= MAGIC_MIME_TYPE;
2242         return buf;
2243 }
2244
2245 /*
2246  * Byteswap an mmap'ed file if needed
2247  */
2248 private void
2249 byteswap(struct magic *magic, uint32_t nmagic)
2250 {
2251         uint32_t i;
2252         for (i = 0; i < nmagic; i++)
2253                 bs1(&magic[i]);
2254 }
2255
2256 /*
2257  * swap a short
2258  */
2259 private uint16_t
2260 swap2(uint16_t sv)
2261 {
2262         uint16_t rv;
2263         uint8_t *s = (uint8_t *)(void *)&sv; 
2264         uint8_t *d = (uint8_t *)(void *)&rv; 
2265         d[0] = s[1];
2266         d[1] = s[0];
2267         return rv;
2268 }
2269
2270 /*
2271  * swap an int
2272  */
2273 private uint32_t
2274 swap4(uint32_t sv)
2275 {
2276         uint32_t rv;
2277         uint8_t *s = (uint8_t *)(void *)&sv; 
2278         uint8_t *d = (uint8_t *)(void *)&rv; 
2279         d[0] = s[3];
2280         d[1] = s[2];
2281         d[2] = s[1];
2282         d[3] = s[0];
2283         return rv;
2284 }
2285
2286 /*
2287  * swap a quad
2288  */
2289 private uint64_t
2290 swap8(uint64_t sv)
2291 {
2292         uint64_t rv;
2293         uint8_t *s = (uint8_t *)(void *)&sv; 
2294         uint8_t *d = (uint8_t *)(void *)&rv; 
2295 #if 0
2296         d[0] = s[3];
2297         d[1] = s[2];
2298         d[2] = s[1];
2299         d[3] = s[0];
2300         d[4] = s[7];
2301         d[5] = s[6];
2302         d[6] = s[5];
2303         d[7] = s[4];
2304 #else
2305         d[0] = s[7];
2306         d[1] = s[6];
2307         d[2] = s[5];
2308         d[3] = s[4];
2309         d[4] = s[3];
2310         d[5] = s[2];
2311         d[6] = s[1];
2312         d[7] = s[0];
2313 #endif
2314         return rv;
2315 }
2316
2317 /*
2318  * byteswap a single magic entry
2319  */
2320 private void
2321 bs1(struct magic *m)
2322 {
2323         m->cont_level = swap2(m->cont_level);
2324         m->offset = swap4((uint32_t)m->offset);
2325         m->in_offset = swap4((uint32_t)m->in_offset);
2326         m->lineno = swap4((uint32_t)m->lineno);
2327         if (IS_STRING(m->type)) {
2328                 m->str_range = swap4(m->str_range);
2329                 m->str_flags = swap4(m->str_flags);
2330         }
2331         else {
2332                 m->value.q = swap8(m->value.q);
2333                 m->num_mask = swap8(m->num_mask);
2334         }
2335 }