sendmail: Update master to work with v8.14.4
[dragonfly.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 #ifndef COMPILE_ONLY
598                 /* binary test if pattern is not text */
599                 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
600                     NULL) <= 0)
601                         mstart->flag |= BINTEST;
602 #endif
603                 break;
604         case FILE_DEFAULT:
605                 /* can't deduce anything; we shouldn't see this at the
606                    top level anyway */
607                 break;
608         case FILE_INVALID:
609         default:
610                 /* invalid search type, but no need to complain here */
611                 break;
612         }
613 }
614
615 /*
616  * Load and parse one file.
617  */
618 private void
619 load_1(struct magic_set *ms, int action, const char *fn, int *errs,
620    struct magic_entry **marray, uint32_t *marraycount)
621 {
622         char line[BUFSIZ];
623         size_t lineno = 0;
624         FILE *f = fopen(ms->file = fn, "r");
625         if (f == NULL) {
626                 if (errno != ENOENT)
627                         file_error(ms, errno, "cannot read magic file `%s'",
628                                    fn);
629                 (*errs)++;
630         } else {
631                 /* read and parse this file */
632                 for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
633                         size_t len;
634                         len = strlen(line);
635                         if (len == 0) /* null line, garbage, etc */
636                                 continue;
637                         if (line[len - 1] == '\n') {
638                                 lineno++;
639                                 line[len - 1] = '\0'; /* delete newline */
640                         }
641                         if (line[0] == '\0')    /* empty, do not parse */
642                                 continue;
643                         if (line[0] == '#')     /* comment, do not parse */
644                                 continue;
645                         if (line[0] == '!' && line[1] == ':') {
646                                 size_t i;
647
648                                 for (i = 0; bang[i].name != NULL; i++) {
649                                         if (len - 2 > bang[i].len &&
650                                             memcmp(bang[i].name, line + 2,
651                                             bang[i].len) == 0)
652                                                 break;
653                                 }
654                                 if (bang[i].name == NULL) {
655                                         file_error(ms, 0,
656                                             "Unknown !: entry `%s'", line);
657                                         (*errs)++;
658                                         continue;
659                                 }
660                                 if (*marraycount == 0) {
661                                         file_error(ms, 0,
662                                             "No current entry for :!%s type",
663                                                 bang[i].name);
664                                         (*errs)++;
665                                         continue;
666                                 }
667                                 if ((*bang[i].fun)(ms, 
668                                     &(*marray)[*marraycount - 1],
669                                     line + bang[i].len + 2) != 0) {
670                                         (*errs)++;
671                                         continue;
672                                 }
673                                 continue;
674                         }
675                         if (parse(ms, marray, marraycount, line, lineno,
676                             action) != 0)
677                                 (*errs)++;
678                 }
679
680                 (void)fclose(f);
681         }
682 }
683
684 /*
685  * parse a file or directory of files
686  * const char *fn: name of magic file or directory
687  */
688 private int
689 apprentice_load(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
690     const char *fn, int action)
691 {
692         int errs = 0;
693         struct magic_entry *marray;
694         uint32_t marraycount, i, mentrycount = 0, starttest;
695         size_t slen;
696         char subfn[MAXPATHLEN];
697         struct stat st;
698         DIR *dir;
699         struct dirent *d;
700
701         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
702
703         maxmagic = MAXMAGIS;
704         if ((marray = CAST(struct magic_entry *, calloc(maxmagic,
705             sizeof(*marray)))) == NULL) {
706                 file_oomem(ms, maxmagic * sizeof(*marray));
707                 return -1;
708         }
709         marraycount = 0;
710
711         /* print silly verbose header for USG compat. */
712         if (action == FILE_CHECK)
713                 (void)fprintf(stderr, "%s\n", usg_hdr);
714
715         /* load directory or file */
716         /* FIXME: Read file names and sort them to prevent
717            non-determinism. See Debian bug #488562. */
718         if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
719                 dir = opendir(fn);
720                 if (dir) {
721                         while ((d = readdir(dir)) != NULL) {
722                                 snprintf(subfn, sizeof(subfn), "%s/%s",
723                                     fn, d->d_name);
724                                 if (stat(subfn, &st) == 0 &&
725                                     S_ISREG(st.st_mode)) {
726                                         load_1(ms, action, subfn, &errs,
727                                             &marray, &marraycount);
728                                 }
729                         }
730                         closedir(dir);
731                 } else
732                         errs++;
733         } else
734                 load_1(ms, action, fn, &errs, &marray, &marraycount);
735         if (errs)
736                 goto out;
737
738         /* Set types of tests */
739         for (i = 0; i < marraycount; ) {
740                 if (marray[i].mp->cont_level != 0) {
741                         i++;
742                         continue;
743                 }
744
745                 starttest = i;
746                 do {
747                         static const char text[] = "text";
748                         static const char binary[] = "binary";
749                         static const size_t len = sizeof(text);
750                         set_test_type(marray[starttest].mp, marray[i].mp);
751                         if ((ms->flags & MAGIC_DEBUG) == 0)
752                                 continue;
753                         (void)fprintf(stderr, "%s%s%s: %s\n",
754                             marray[i].mp->mimetype,
755                             marray[i].mp->mimetype[0] == '\0' ? "" : "; ",
756                             marray[i].mp->desc[0] ? marray[i].mp->desc :
757                             "(no description)",
758                             marray[i].mp->flag & BINTEST ? binary : text);
759                         if (marray[i].mp->flag & BINTEST) {
760                                 char *p = strstr(marray[i].mp->desc, text);
761                                 if (p && (p == marray[i].mp->desc ||
762                                     isspace((unsigned char)p[-1])) &&
763                                     (p + len - marray[i].mp->desc == 
764                                     MAXstring || (p[len] == '\0' ||
765                                     isspace((unsigned char)p[len]))))
766                                         (void)fprintf(stderr, "*** Possible "
767                                             "binary test for text type\n");
768                         }
769                 } while (++i < marraycount && marray[i].mp->cont_level != 0);
770         }
771
772         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
773
774         /*
775          * Make sure that any level 0 "default" line is last (if one exists).
776          */
777         for (i = 0; i < marraycount; i++) {
778                 if (marray[i].mp->cont_level == 0 &&
779                     marray[i].mp->type == FILE_DEFAULT) {
780                         while (++i < marraycount)
781                                 if (marray[i].mp->cont_level == 0)
782                                         break;
783                         if (i != marraycount) {
784                                 ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
785                                 file_magwarn(ms,
786                                     "level 0 \"default\" did not sort last");
787                         }
788                         break;                                      
789                 }
790         }
791
792         for (i = 0; i < marraycount; i++)
793                 mentrycount += marray[i].cont_count;
794
795         slen = sizeof(**magicp) * mentrycount;
796         if ((*magicp = CAST(struct magic *, malloc(slen))) == NULL) {
797                 file_oomem(ms, slen);
798                 errs++;
799                 goto out;
800         }
801
802         mentrycount = 0;
803         for (i = 0; i < marraycount; i++) {
804                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
805                     marray[i].cont_count * sizeof(**magicp));
806                 mentrycount += marray[i].cont_count;
807         }
808 out:
809         for (i = 0; i < marraycount; i++)
810                 free(marray[i].mp);
811         free(marray);
812         if (errs) {
813                 *magicp = NULL;
814                 *nmagicp = 0;
815                 return errs;
816         } else {
817                 *nmagicp = mentrycount;
818                 return 0;
819         }
820
821 }
822
823 /*
824  * extend the sign bit if the comparison is to be signed
825  */
826 protected uint64_t
827 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
828 {
829         if (!(m->flag & UNSIGNED)) {
830                 switch(m->type) {
831                 /*
832                  * Do not remove the casts below.  They are
833                  * vital.  When later compared with the data,
834                  * the sign extension must have happened.
835                  */
836                 case FILE_BYTE:
837                         v = (char) v;
838                         break;
839                 case FILE_SHORT:
840                 case FILE_BESHORT:
841                 case FILE_LESHORT:
842                         v = (short) v;
843                         break;
844                 case FILE_DATE:
845                 case FILE_BEDATE:
846                 case FILE_LEDATE:
847                 case FILE_MEDATE:
848                 case FILE_LDATE:
849                 case FILE_BELDATE:
850                 case FILE_LELDATE:
851                 case FILE_MELDATE:
852                 case FILE_LONG:
853                 case FILE_BELONG:
854                 case FILE_LELONG:
855                 case FILE_MELONG:
856                 case FILE_FLOAT:
857                 case FILE_BEFLOAT:
858                 case FILE_LEFLOAT:
859                         v = (int32_t) v;
860                         break;
861                 case FILE_QUAD:
862                 case FILE_BEQUAD:
863                 case FILE_LEQUAD:
864                 case FILE_QDATE:
865                 case FILE_QLDATE:
866                 case FILE_BEQDATE:
867                 case FILE_BEQLDATE:
868                 case FILE_LEQDATE:
869                 case FILE_LEQLDATE:
870                 case FILE_DOUBLE:
871                 case FILE_BEDOUBLE:
872                 case FILE_LEDOUBLE:
873                         v = (int64_t) v;
874                         break;
875                 case FILE_STRING:
876                 case FILE_PSTRING:
877                 case FILE_BESTRING16:
878                 case FILE_LESTRING16:
879                 case FILE_REGEX:
880                 case FILE_SEARCH:
881                 case FILE_DEFAULT:
882                 case FILE_INDIRECT:
883                         break;
884                 default:
885                         if (ms->flags & MAGIC_CHECK)
886                             file_magwarn(ms, "cannot happen: m->type=%d\n",
887                                     m->type);
888                         return ~0U;
889                 }
890         }
891         return v;
892 }
893
894 private int
895 string_modifier_check(struct magic_set *ms, struct magic *m)
896 {
897         if ((ms->flags & MAGIC_CHECK) == 0)
898                 return 0;
899
900         switch (m->type) {
901         case FILE_BESTRING16:
902         case FILE_LESTRING16:
903                 if (m->str_flags != 0) {
904                         file_magwarn(ms,
905                             "no modifiers allowed for 16-bit strings\n");
906                         return -1;
907                 }
908                 break;
909         case FILE_STRING:
910         case FILE_PSTRING:
911                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
912                         file_magwarn(ms,
913                             "'/%c' only allowed on regex and search\n",
914                             CHAR_REGEX_OFFSET_START);
915                         return -1;
916                 }
917                 break;
918         case FILE_SEARCH:
919                 if (m->str_range == 0) {
920                         file_magwarn(ms,
921                             "missing range; defaulting to %d\n",
922                             STRING_DEFAULT_RANGE);
923                         m->str_range = STRING_DEFAULT_RANGE;
924                         return -1;
925                 }
926                 break;
927         case FILE_REGEX:
928                 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
929                         file_magwarn(ms, "'/%c' not allowed on regex\n",
930                             CHAR_COMPACT_BLANK);
931                         return -1;
932                 }
933                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
934                         file_magwarn(ms, "'/%c' not allowed on regex\n",
935                             CHAR_COMPACT_OPTIONAL_BLANK);
936                         return -1;
937                 }
938                 break;
939         default:
940                 file_magwarn(ms, "coding error: m->type=%d\n",
941                     m->type);
942                 return -1;
943         }
944         return 0;
945 }
946
947 private int
948 get_op(char c)
949 {
950         switch (c) {
951         case '&':
952                 return FILE_OPAND;
953         case '|':
954                 return FILE_OPOR;
955         case '^':
956                 return FILE_OPXOR;
957         case '+':
958                 return FILE_OPADD;
959         case '-':
960                 return FILE_OPMINUS;
961         case '*':
962                 return FILE_OPMULTIPLY;
963         case '/':
964                 return FILE_OPDIVIDE;
965         case '%':
966                 return FILE_OPMODULO;
967         default:
968                 return -1;
969         }
970 }
971
972 #ifdef ENABLE_CONDITIONALS
973 private int
974 get_cond(const char *l, const char **t)
975 {
976         static const struct cond_tbl_s {
977                 char name[8];
978                 size_t len;
979                 int cond;
980         } cond_tbl[] = {
981                 { "if",         2,      COND_IF },
982                 { "elif",       4,      COND_ELIF },
983                 { "else",       4,      COND_ELSE },
984                 { "",           0,      COND_NONE },
985         };
986         const struct cond_tbl_s *p;
987
988         for (p = cond_tbl; p->len; p++) {
989                 if (strncmp(l, p->name, p->len) == 0 &&
990                     isspace((unsigned char)l[p->len])) {
991                         if (t)
992                                 *t = l + p->len;
993                         break;
994                 }
995         }
996         return p->cond;
997 }
998
999 private int
1000 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
1001 {
1002         int last_cond;
1003         last_cond = ms->c.li[cont_level].last_cond;
1004
1005         switch (cond) {
1006         case COND_IF:
1007                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1008                         if (ms->flags & MAGIC_CHECK)
1009                                 file_magwarn(ms, "syntax error: `if'");
1010                         return -1;
1011                 }
1012                 last_cond = COND_IF;
1013                 break;
1014
1015         case COND_ELIF:
1016                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1017                         if (ms->flags & MAGIC_CHECK)
1018                                 file_magwarn(ms, "syntax error: `elif'");
1019                         return -1;
1020                 }
1021                 last_cond = COND_ELIF;
1022                 break;
1023
1024         case COND_ELSE:
1025                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1026                         if (ms->flags & MAGIC_CHECK)
1027                                 file_magwarn(ms, "syntax error: `else'");
1028                         return -1;
1029                 }
1030                 last_cond = COND_NONE;
1031                 break;
1032
1033         case COND_NONE:
1034                 last_cond = COND_NONE;
1035                 break;
1036         }
1037
1038         ms->c.li[cont_level].last_cond = last_cond;
1039         return 0;
1040 }
1041 #endif /* ENABLE_CONDITIONALS */
1042
1043 /*
1044  * parse one line from magic file, put into magic[index++] if valid
1045  */
1046 private int
1047 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
1048     const char *line, size_t lineno, int action)
1049 {
1050 #ifdef ENABLE_CONDITIONALS
1051         static uint32_t last_cont_level = 0;
1052 #endif
1053         size_t i;
1054         struct magic_entry *me;
1055         struct magic *m;
1056         const char *l = line;
1057         char *t;
1058         int op;
1059         uint32_t cont_level;
1060
1061         cont_level = 0;
1062
1063         while (*l == '>') {
1064                 ++l;            /* step over */
1065                 cont_level++; 
1066         }
1067 #ifdef ENABLE_CONDITIONALS
1068         if (cont_level == 0 || cont_level > last_cont_level)
1069                 if (file_check_mem(ms, cont_level) == -1)
1070                         return -1;
1071         last_cont_level = cont_level;
1072 #endif
1073
1074 #define ALLOC_CHUNK     (size_t)10
1075 #define ALLOC_INCR      (size_t)200
1076
1077         if (cont_level != 0) {
1078                 if (*nmentryp == 0) {
1079                         file_error(ms, 0, "No current entry for continuation");
1080                         return -1;
1081                 }
1082                 me = &(*mentryp)[*nmentryp - 1];
1083                 if (me->cont_count == me->max_count) {
1084                         struct magic *nm;
1085                         size_t cnt = me->max_count + ALLOC_CHUNK;
1086                         if ((nm = CAST(struct magic *, realloc(me->mp,
1087                             sizeof(*nm) * cnt))) == NULL) {
1088                                 file_oomem(ms, sizeof(*nm) * cnt);
1089                                 return -1;
1090                         }
1091                         me->mp = m = nm;
1092                         me->max_count = cnt;
1093                 }
1094                 m = &me->mp[me->cont_count++];
1095                 (void)memset(m, 0, sizeof(*m));
1096                 m->cont_level = cont_level;
1097         } else {
1098                 if (*nmentryp == maxmagic) {
1099                         struct magic_entry *mp;
1100
1101                         maxmagic += ALLOC_INCR;
1102                         if ((mp = CAST(struct magic_entry *,
1103                             realloc(*mentryp, sizeof(*mp) * maxmagic))) ==
1104                             NULL) {
1105                                 file_oomem(ms, sizeof(*mp) * maxmagic);
1106                                 return -1;
1107                         }
1108                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
1109                             ALLOC_INCR);
1110                         *mentryp = mp;
1111                 }
1112                 me = &(*mentryp)[*nmentryp];
1113                 if (me->mp == NULL) {
1114                         size_t len = sizeof(*m) * ALLOC_CHUNK;
1115                         if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1116                                 file_oomem(ms, len);
1117                                 return -1;
1118                         }
1119                         me->mp = m;
1120                         me->max_count = ALLOC_CHUNK;
1121                 } else
1122                         m = me->mp;
1123                 (void)memset(m, 0, sizeof(*m));
1124                 m->factor_op = FILE_FACTOR_OP_NONE;
1125                 m->cont_level = 0;
1126                 me->cont_count = 1;
1127         }
1128         m->lineno = lineno;
1129
1130         if (*l == '&') {  /* m->cont_level == 0 checked below. */
1131                 ++l;            /* step over */
1132                 m->flag |= OFFADD;
1133         }
1134         if (*l == '(') {
1135                 ++l;            /* step over */
1136                 m->flag |= INDIR;
1137                 if (m->flag & OFFADD)
1138                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1139
1140                 if (*l == '&') {  /* m->cont_level == 0 checked below */
1141                         ++l;            /* step over */
1142                         m->flag |= OFFADD;
1143                 }
1144         }
1145         /* Indirect offsets are not valid at level 0. */
1146         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
1147                 if (ms->flags & MAGIC_CHECK)
1148                         file_magwarn(ms, "relative offset at level 0");
1149
1150         /* get offset, then skip over it */
1151         m->offset = (uint32_t)strtoul(l, &t, 0);
1152         if (l == t)
1153                 if (ms->flags & MAGIC_CHECK)
1154                         file_magwarn(ms, "offset `%s' invalid", l);
1155         l = t;
1156
1157         if (m->flag & INDIR) {
1158                 m->in_type = FILE_LONG;
1159                 m->in_offset = 0;
1160                 /*
1161                  * read [.lbs][+-]nnnnn)
1162                  */
1163                 if (*l == '.') {
1164                         l++;
1165                         switch (*l) {
1166                         case 'l':
1167                                 m->in_type = FILE_LELONG;
1168                                 break;
1169                         case 'L':
1170                                 m->in_type = FILE_BELONG;
1171                                 break;
1172                         case 'm':
1173                                 m->in_type = FILE_MELONG;
1174                                 break;
1175                         case 'h':
1176                         case 's':
1177                                 m->in_type = FILE_LESHORT;
1178                                 break;
1179                         case 'H':
1180                         case 'S':
1181                                 m->in_type = FILE_BESHORT;
1182                                 break;
1183                         case 'c':
1184                         case 'b':
1185                         case 'C':
1186                         case 'B':
1187                                 m->in_type = FILE_BYTE;
1188                                 break;
1189                         case 'e':
1190                         case 'f':
1191                         case 'g':
1192                                 m->in_type = FILE_LEDOUBLE;
1193                                 break;
1194                         case 'E':
1195                         case 'F':
1196                         case 'G':
1197                                 m->in_type = FILE_BEDOUBLE;
1198                                 break;
1199                         case 'i':
1200                                 m->in_type = FILE_LEID3;
1201                                 break;
1202                         case 'I':
1203                                 m->in_type = FILE_BEID3;
1204                                 break;
1205                         default:
1206                                 if (ms->flags & MAGIC_CHECK)
1207                                         file_magwarn(ms,
1208                                             "indirect offset type `%c' invalid",
1209                                             *l);
1210                                 break;
1211                         }
1212                         l++;
1213                 }
1214
1215                 m->in_op = 0;
1216                 if (*l == '~') {
1217                         m->in_op |= FILE_OPINVERSE;
1218                         l++;
1219                 }
1220                 if ((op = get_op(*l)) != -1) {
1221                         m->in_op |= op;
1222                         l++;
1223                 }
1224                 if (*l == '(') {
1225                         m->in_op |= FILE_OPINDIRECT;
1226                         l++;
1227                 }
1228                 if (isdigit((unsigned char)*l) || *l == '-') {
1229                         m->in_offset = (int32_t)strtol(l, &t, 0);
1230                         if (l == t)
1231                                 if (ms->flags & MAGIC_CHECK)
1232                                         file_magwarn(ms,
1233                                             "in_offset `%s' invalid", l);
1234                         l = t;
1235                 }
1236                 if (*l++ != ')' || 
1237                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1238                         if (ms->flags & MAGIC_CHECK)
1239                                 file_magwarn(ms,
1240                                     "missing ')' in indirect offset");
1241         }
1242         EATAB;
1243
1244 #ifdef ENABLE_CONDITIONALS
1245         m->cond = get_cond(l, &l);
1246         if (check_cond(ms, m->cond, cont_level) == -1)
1247                 return -1;
1248
1249         EATAB;
1250 #endif
1251
1252         if (*l == 'u') {
1253                 ++l;
1254                 m->flag |= UNSIGNED;
1255         }
1256
1257         m->type = get_type(l, &l);
1258         if (m->type == FILE_INVALID) {
1259                 if (ms->flags & MAGIC_CHECK)
1260                         file_magwarn(ms, "type `%s' invalid", l);
1261                 return -1;
1262         }
1263
1264         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1265         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1266
1267         m->mask_op = 0;
1268         if (*l == '~') {
1269                 if (!IS_STRING(m->type))
1270                         m->mask_op |= FILE_OPINVERSE;
1271                 else if (ms->flags & MAGIC_CHECK)
1272                         file_magwarn(ms, "'~' invalid for string types");
1273                 ++l;
1274         }
1275         m->str_range = 0;
1276         m->str_flags = 0;
1277         m->num_mask = 0;
1278         if ((op = get_op(*l)) != -1) {
1279                 if (!IS_STRING(m->type)) {
1280                         uint64_t val;
1281                         ++l;
1282                         m->mask_op |= op;
1283                         val = (uint64_t)strtoull(l, &t, 0);
1284                         l = t;
1285                         m->num_mask = file_signextend(ms, m, val);
1286                         eatsize(&l);
1287                 }
1288                 else if (op == FILE_OPDIVIDE) {
1289                         int have_range = 0;
1290                         while (!isspace((unsigned char)*++l)) {
1291                                 switch (*l) {
1292                                 case '0':  case '1':  case '2':
1293                                 case '3':  case '4':  case '5':
1294                                 case '6':  case '7':  case '8':
1295                                 case '9':
1296                                         if (have_range &&
1297                                             (ms->flags & MAGIC_CHECK))
1298                                                 file_magwarn(ms,
1299                                                     "multiple ranges");
1300                                         have_range = 1;
1301                                         m->str_range = strtoul(l, &t, 0);
1302                                         if (m->str_range == 0)
1303                                                 file_magwarn(ms,
1304                                                     "zero range");
1305                                         l = t - 1;
1306                                         break;
1307                                 case CHAR_COMPACT_BLANK:
1308                                         m->str_flags |= STRING_COMPACT_BLANK;
1309                                         break;
1310                                 case CHAR_COMPACT_OPTIONAL_BLANK:
1311                                         m->str_flags |=
1312                                             STRING_COMPACT_OPTIONAL_BLANK;
1313                                         break;
1314                                 case CHAR_IGNORE_LOWERCASE:
1315                                         m->str_flags |= STRING_IGNORE_LOWERCASE;
1316                                         break;
1317                                 case CHAR_IGNORE_UPPERCASE:
1318                                         m->str_flags |= STRING_IGNORE_UPPERCASE;
1319                                         break;
1320                                 case CHAR_REGEX_OFFSET_START:
1321                                         m->str_flags |= REGEX_OFFSET_START;
1322                                         break;
1323                                 default:
1324                                         if (ms->flags & MAGIC_CHECK)
1325                                                 file_magwarn(ms,
1326                                                 "string extension `%c' invalid",
1327                                                 *l);
1328                                         return -1;
1329                                 }
1330                                 /* allow multiple '/' for readability */
1331                                 if (l[1] == '/' &&
1332                                     !isspace((unsigned char)l[2]))
1333                                         l++;
1334                         }
1335                         if (string_modifier_check(ms, m) == -1)
1336                                 return -1;
1337                 }
1338                 else {
1339                         if (ms->flags & MAGIC_CHECK)
1340                                 file_magwarn(ms, "invalid string op: %c", *t);
1341                         return -1;
1342                 }
1343         }
1344         /*
1345          * We used to set mask to all 1's here, instead let's just not do
1346          * anything if mask = 0 (unless you have a better idea)
1347          */
1348         EATAB;
1349   
1350         switch (*l) {
1351         case '>':
1352         case '<':
1353                 m->reln = *l;
1354                 ++l;
1355                 if (*l == '=') {
1356                         if (ms->flags & MAGIC_CHECK) {
1357                                 file_magwarn(ms, "%c= not supported",
1358                                     m->reln);
1359                                 return -1;
1360                         }
1361                    ++l;
1362                 }
1363                 break;
1364         /* Old-style anding: "0 byte &0x80 dynamically linked" */
1365         case '&':
1366         case '^':
1367         case '=':
1368                 m->reln = *l;
1369                 ++l;
1370                 if (*l == '=') {
1371                    /* HP compat: ignore &= etc. */
1372                    ++l;
1373                 }
1374                 break;
1375         case '!':
1376                 m->reln = *l;
1377                 ++l;
1378                 break;
1379         default:
1380                 m->reln = '=';  /* the default relation */
1381                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
1382                     isspace((unsigned char)l[1])) || !l[1])) {
1383                         m->reln = *l;
1384                         ++l;
1385                 }
1386                 break;
1387         }
1388         /*
1389          * Grab the value part, except for an 'x' reln.
1390          */
1391         if (m->reln != 'x' && getvalue(ms, m, &l, action))
1392                 return -1;
1393
1394         /*
1395          * TODO finish this macro and start using it!
1396          * #define offsetcheck {if (offset > HOWMANY-1) 
1397          *      magwarn("offset too big"); }
1398          */
1399
1400         /*
1401          * Now get last part - the description
1402          */
1403         EATAB;
1404         if (l[0] == '\b') {
1405                 ++l;
1406                 m->flag |= NOSPACE;
1407         } else if ((l[0] == '\\') && (l[1] == 'b')) {
1408                 ++l;
1409                 ++l;
1410                 m->flag |= NOSPACE;
1411         }
1412         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
1413                 continue;
1414         if (i == sizeof(m->desc)) {
1415                 m->desc[sizeof(m->desc) - 1] = '\0';
1416                 if (ms->flags & MAGIC_CHECK)
1417                         file_magwarn(ms, "description `%s' truncated", m->desc);
1418         }
1419
1420         /*
1421          * We only do this check while compiling, or if any of the magic
1422          * files were not compiled.
1423          */
1424         if (ms->flags & MAGIC_CHECK) {
1425                 if (check_format(ms, m) == -1)
1426                         return -1;
1427         }
1428 #ifndef COMPILE_ONLY
1429         if (action == FILE_CHECK) {
1430                 file_mdump(m);
1431         }
1432 #endif
1433         m->mimetype[0] = '\0';          /* initialise MIME type to none */
1434         if (m->cont_level == 0)
1435                 ++(*nmentryp);          /* make room for next */
1436         return 0;
1437 }
1438
1439 /*
1440  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
1441  * if valid
1442  */
1443 private int
1444 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
1445 {
1446         const char *l = line;
1447         char *el;
1448         unsigned long factor;
1449         struct magic *m = &me->mp[0];
1450
1451         if (m->factor_op != FILE_FACTOR_OP_NONE) {
1452                 file_magwarn(ms,
1453                     "Current entry already has a strength type: %c %d",
1454                     m->factor_op, m->factor);
1455                 return -1;
1456         }
1457         EATAB;
1458         switch (*l) {
1459         case FILE_FACTOR_OP_NONE:
1460         case FILE_FACTOR_OP_PLUS:
1461         case FILE_FACTOR_OP_MINUS:
1462         case FILE_FACTOR_OP_TIMES:
1463         case FILE_FACTOR_OP_DIV:
1464                 m->factor_op = *l++;
1465                 break;
1466         default:
1467                 file_magwarn(ms, "Unknown factor op `%c'", *l);
1468                 return -1;
1469         }
1470         EATAB;
1471         factor = strtoul(l, &el, 0);
1472         if (factor > 255) {
1473                 file_magwarn(ms, "Too large factor `%lu'", factor);
1474                 goto out;
1475         }
1476         if (*el && !isspace((unsigned char)*el)) {
1477                 file_magwarn(ms, "Bad factor `%s'", l);
1478                 goto out;
1479         }
1480         m->factor = (uint8_t)factor;
1481         if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
1482                 file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
1483                     m->factor_op, m->factor);
1484                 goto out;
1485         }
1486         return 0;
1487 out:
1488         m->factor_op = FILE_FACTOR_OP_NONE;
1489         m->factor = 0;
1490         return -1;
1491 }
1492
1493 /*
1494  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into magic[index - 1]
1495  */
1496 private int
1497 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
1498 {
1499         size_t i;
1500         const char *l = line;
1501         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1502
1503         if (m->apple[0] != '\0') {
1504                 file_magwarn(ms, "Current entry already has a APPLE type `%.8s',"
1505                     " new type `%s'", m->mimetype, l);
1506                 return -1;
1507         }       
1508
1509         EATAB;
1510         for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1511              || strchr("-+/.", *l)) && i < sizeof(m->apple); m->apple[i++] = *l++)
1512                 continue;
1513         if (i == sizeof(m->apple) && *l) {
1514                 if (ms->flags & MAGIC_CHECK)
1515                         file_magwarn(ms, "APPLE type `%s' truncated %zu",
1516                             line, i);
1517         }
1518
1519         if (i > 0)
1520                 return 0;
1521         else
1522                 return -1;
1523 }
1524
1525 /*
1526  * parse a MIME annotation line from magic file, put into magic[index - 1]
1527  * if valid
1528  */
1529 private int
1530 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
1531 {
1532         size_t i;
1533         const char *l = line;
1534         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
1535
1536         if (m->mimetype[0] != '\0') {
1537                 file_magwarn(ms, "Current entry already has a MIME type `%s',"
1538                     " new type `%s'", m->mimetype, l);
1539                 return -1;
1540         }       
1541
1542         EATAB;
1543         for (i = 0; *l && ((isascii((unsigned char)*l) && isalnum((unsigned char)*l))
1544              || strchr("-+/.", *l)) && i < sizeof(m->mimetype); m->mimetype[i++] = *l++)
1545                 continue;
1546         if (i == sizeof(m->mimetype)) {
1547                 m->desc[sizeof(m->mimetype) - 1] = '\0';
1548                 if (ms->flags & MAGIC_CHECK)
1549                         file_magwarn(ms, "MIME type `%s' truncated %zu",
1550                             m->mimetype, i);
1551         } else
1552                 m->mimetype[i] = '\0';
1553
1554         if (i > 0)
1555                 return 0;
1556         else
1557                 return -1;
1558 }
1559
1560 private int
1561 check_format_type(const char *ptr, int type)
1562 {
1563         int quad = 0;
1564         if (*ptr == '\0') {
1565                 /* Missing format string; bad */
1566                 return -1;
1567         }
1568
1569         switch (type) {
1570         case FILE_FMT_QUAD:
1571                 quad = 1;
1572                 /*FALLTHROUGH*/
1573         case FILE_FMT_NUM:
1574                 if (*ptr == '-')
1575                         ptr++;
1576                 if (*ptr == '.')
1577                         ptr++;
1578                 while (isdigit((unsigned char)*ptr)) ptr++;
1579                 if (*ptr == '.')
1580                         ptr++;
1581                 while (isdigit((unsigned char)*ptr)) ptr++;
1582                 if (quad) {
1583                         if (*ptr++ != 'l')
1584                                 return -1;
1585                         if (*ptr++ != 'l')
1586                                 return -1;
1587                 }
1588         
1589                 switch (*ptr++) {
1590                 case 'l':
1591                         switch (*ptr++) {
1592                         case 'i':
1593                         case 'd':
1594                         case 'u':
1595                         case 'x':
1596                         case 'X':
1597                                 return 0;
1598                         default:
1599                                 return -1;
1600                         }
1601                 
1602                 case 'h':
1603                         switch (*ptr++) {
1604                         case 'h':
1605                                 switch (*ptr++) {
1606                                 case 'i':
1607                                 case 'd':
1608                                 case 'u':
1609                                 case 'x':
1610                                 case 'X':
1611                                         return 0;
1612                                 default:
1613                                         return -1;
1614                                 }
1615                         case 'd':
1616                                 return 0;
1617                         default:
1618                                 return -1;
1619                         }
1620
1621                 case 'i':
1622                 case 'c':
1623                 case 'd':
1624                 case 'u':
1625                 case 'x':
1626                 case 'X':
1627                         return 0;
1628                         
1629                 default:
1630                         return -1;
1631                 }
1632                 
1633         case FILE_FMT_FLOAT:
1634         case FILE_FMT_DOUBLE:
1635                 if (*ptr == '-')
1636                         ptr++;
1637                 if (*ptr == '.')
1638                         ptr++;
1639                 while (isdigit((unsigned char)*ptr)) ptr++;
1640                 if (*ptr == '.')
1641                         ptr++;
1642                 while (isdigit((unsigned char)*ptr)) ptr++;
1643         
1644                 switch (*ptr++) {
1645                 case 'e':
1646                 case 'E':
1647                 case 'f':
1648                 case 'F':
1649                 case 'g':
1650                 case 'G':
1651                         return 0;
1652                         
1653                 default:
1654                         return -1;
1655                 }
1656                 
1657
1658         case FILE_FMT_STR:
1659                 if (*ptr == '-')
1660                         ptr++;
1661                 while (isdigit((unsigned char )*ptr))
1662                         ptr++;
1663                 if (*ptr == '.') {
1664                         ptr++;
1665                         while (isdigit((unsigned char )*ptr))
1666                                 ptr++;
1667                 }
1668                 
1669                 switch (*ptr++) {
1670                 case 's':
1671                         return 0;
1672                 default:
1673                         return -1;
1674                 }
1675                 
1676         default:
1677                 /* internal error */
1678                 abort();
1679         }
1680         /*NOTREACHED*/
1681         return -1;
1682 }
1683         
1684 /*
1685  * Check that the optional printf format in description matches
1686  * the type of the magic.
1687  */
1688 private int
1689 check_format(struct magic_set *ms, struct magic *m)
1690 {
1691         char *ptr;
1692
1693         for (ptr = m->desc; *ptr; ptr++)
1694                 if (*ptr == '%')
1695                         break;
1696         if (*ptr == '\0') {
1697                 /* No format string; ok */
1698                 return 1;
1699         }
1700
1701         assert(file_nformats == file_nnames);
1702
1703         if (m->type >= file_nformats) {
1704                 file_magwarn(ms, "Internal error inconsistency between "
1705                     "m->type and format strings");              
1706                 return -1;
1707         }
1708         if (file_formats[m->type] == FILE_FMT_NONE) {
1709                 file_magwarn(ms, "No format string for `%s' with description "
1710                     "`%s'", m->desc, file_names[m->type]);
1711                 return -1;
1712         }
1713
1714         ptr++;
1715         if (check_format_type(ptr, file_formats[m->type]) == -1) {
1716                 /*
1717                  * TODO: this error message is unhelpful if the format
1718                  * string is not one character long
1719                  */
1720                 file_magwarn(ms, "Printf format `%c' is not valid for type "
1721                     "`%s' in description `%s'", *ptr ? *ptr : '?',
1722                     file_names[m->type], m->desc);
1723                 return -1;
1724         }
1725         
1726         for (; *ptr; ptr++) {
1727                 if (*ptr == '%') {
1728                         file_magwarn(ms,
1729                             "Too many format strings (should have at most one) "
1730                             "for `%s' with description `%s'",
1731                             file_names[m->type], m->desc);
1732                         return -1;
1733                 }
1734         }
1735         return 0;
1736 }
1737
1738 /* 
1739  * Read a numeric value from a pointer, into the value union of a magic 
1740  * pointer, according to the magic type.  Update the string pointer to point 
1741  * just after the number read.  Return 0 for success, non-zero for failure.
1742  */
1743 private int
1744 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1745 {
1746         switch (m->type) {
1747         case FILE_BESTRING16:
1748         case FILE_LESTRING16:
1749         case FILE_STRING:
1750         case FILE_PSTRING:
1751         case FILE_REGEX:
1752         case FILE_SEARCH:
1753                 *p = getstr(ms, m, *p, action == FILE_COMPILE);
1754                 if (*p == NULL) {
1755                         if (ms->flags & MAGIC_CHECK)
1756                                 file_magwarn(ms, "cannot get string from `%s'",
1757                                     m->value.s);
1758                         return -1;
1759                 }
1760                 return 0;
1761         case FILE_FLOAT:
1762         case FILE_BEFLOAT:
1763         case FILE_LEFLOAT:
1764                 if (m->reln != 'x') {
1765                         char *ep;
1766 #if defined(HAVE_STRTOF) && !defined(COMPILE_ONLY)
1767                         m->value.f = strtof(*p, &ep);
1768 #else
1769                         m->value.f = (float)strtod(*p, &ep);
1770 #endif
1771                         *p = ep;
1772                 }
1773                 return 0;
1774         case FILE_DOUBLE:
1775         case FILE_BEDOUBLE:
1776         case FILE_LEDOUBLE:
1777                 if (m->reln != 'x') {
1778                         char *ep;
1779                         m->value.d = strtod(*p, &ep);
1780                         *p = ep;
1781                 }
1782                 return 0;
1783         default:
1784                 if (m->reln != 'x') {
1785                         char *ep;
1786                         m->value.q = file_signextend(ms, m,
1787                             (uint64_t)strtoull(*p, &ep, 0));
1788                         *p = ep;
1789                         eatsize(p);
1790                 }
1791                 return 0;
1792         }
1793 }
1794
1795 /*
1796  * Convert a string containing C character escapes.  Stop at an unescaped
1797  * space or tab.
1798  * Copy the converted version to "m->value.s", and the length in m->vallen.
1799  * Return updated scan pointer as function result. Warn if set.
1800  */
1801 private const char *
1802 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
1803 {
1804         const char *origs = s;
1805         char    *p = m->value.s;
1806         size_t  plen = sizeof(m->value.s);
1807         char    *origp = p;
1808         char    *pmax = p + plen - 1;
1809         int     c;
1810         int     val;
1811
1812         while ((c = *s++) != '\0') {
1813                 if (isspace((unsigned char) c))
1814                         break;
1815                 if (p >= pmax) {
1816                         file_error(ms, 0, "string too long: `%s'", origs);
1817                         return NULL;
1818                 }
1819                 if (c == '\\') {
1820                         switch(c = *s++) {
1821
1822                         case '\0':
1823                                 if (warn)
1824                                         file_magwarn(ms, "incomplete escape");
1825                                 goto out;
1826
1827                         case '\t':
1828                                 if (warn) {
1829                                         file_magwarn(ms,
1830                                             "escaped tab found, use \\t instead");
1831                                         warn = 0;       /* already did */
1832                                 }
1833                                 /*FALLTHROUGH*/
1834                         default:
1835                                 if (warn) {
1836                                         if (isprint((unsigned char)c)) {
1837                                                 /* Allow escaping of 
1838                                                  * ``relations'' */
1839                                                 if (strchr("<>&^=!", c)
1840                                                     == NULL) {
1841                                                         file_magwarn(ms, "no "
1842                                                             "need to escape "
1843                                                             "`%c'", c);
1844                                                 }
1845                                         } else {
1846                                                 file_magwarn(ms,
1847                                                     "unknown escape sequence: "
1848                                                     "\\%03o", c);
1849                                         }
1850                                 }
1851                                 /*FALLTHROUGH*/
1852                         /* space, perhaps force people to use \040? */
1853                         case ' ':
1854 #if 0
1855                         /*
1856                          * Other things people escape, but shouldn't need to,
1857                          * so we disallow them
1858                          */
1859                         case '\'':
1860                         case '"':
1861                         case '?':
1862 #endif
1863                         /* Relations */
1864                         case '>':
1865                         case '<':
1866                         case '&':
1867                         case '^':
1868                         case '=':
1869                         case '!':
1870                         /* and baskslash itself */
1871                         case '\\':
1872                                 *p++ = (char) c;
1873                                 break;
1874
1875                         case 'a':
1876                                 *p++ = '\a';
1877                                 break;
1878
1879                         case 'b':
1880                                 *p++ = '\b';
1881                                 break;
1882
1883                         case 'f':
1884                                 *p++ = '\f';
1885                                 break;
1886
1887                         case 'n':
1888                                 *p++ = '\n';
1889                                 break;
1890
1891                         case 'r':
1892                                 *p++ = '\r';
1893                                 break;
1894
1895                         case 't':
1896                                 *p++ = '\t';
1897                                 break;
1898
1899                         case 'v':
1900                                 *p++ = '\v';
1901                                 break;
1902
1903                         /* \ and up to 3 octal digits */
1904                         case '0':
1905                         case '1':
1906                         case '2':
1907                         case '3':
1908                         case '4':
1909                         case '5':
1910                         case '6':
1911                         case '7':
1912                                 val = c - '0';
1913                                 c = *s++;  /* try for 2 */
1914                                 if (c >= '0' && c <= '7') {
1915                                         val = (val << 3) | (c - '0');
1916                                         c = *s++;  /* try for 3 */
1917                                         if (c >= '0' && c <= '7')
1918                                                 val = (val << 3) | (c-'0');
1919                                         else
1920                                                 --s;
1921                                 }
1922                                 else
1923                                         --s;
1924                                 *p++ = (char)val;
1925                                 break;
1926
1927                         /* \x and up to 2 hex digits */
1928                         case 'x':
1929                                 val = 'x';      /* Default if no digits */
1930                                 c = hextoint(*s++);     /* Get next char */
1931                                 if (c >= 0) {
1932                                         val = c;
1933                                         c = hextoint(*s++);
1934                                         if (c >= 0)
1935                                                 val = (val << 4) + c;
1936                                         else
1937                                                 --s;
1938                                 } else
1939                                         --s;
1940                                 *p++ = (char)val;
1941                                 break;
1942                         }
1943                 } else
1944                         *p++ = (char)c;
1945         }
1946 out:
1947         *p = '\0';
1948         m->vallen = p - origp;
1949         if (m->type == FILE_PSTRING)
1950                 m->vallen++;
1951         return s;
1952 }
1953
1954
1955 /* Single hex char to int; -1 if not a hex char. */
1956 private int
1957 hextoint(int c)
1958 {
1959         if (!isascii((unsigned char) c))
1960                 return -1;
1961         if (isdigit((unsigned char) c))
1962                 return c - '0';
1963         if ((c >= 'a') && (c <= 'f'))
1964                 return c + 10 - 'a';
1965         if (( c>= 'A') && (c <= 'F'))
1966                 return c + 10 - 'A';
1967         return -1;
1968 }
1969
1970
1971 /*
1972  * Print a string containing C character escapes.
1973  */
1974 protected void
1975 file_showstr(FILE *fp, const char *s, size_t len)
1976 {
1977         char    c;
1978
1979         for (;;) {
1980                 c = *s++;
1981                 if (len == ~0U) {
1982                         if (c == '\0')
1983                                 break;
1984                 }
1985                 else  {
1986                         if (len-- == 0)
1987                                 break;
1988                 }
1989                 if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
1990                         (void) fputc(c, fp);
1991                 else {
1992                         (void) fputc('\\', fp);
1993                         switch (c) {
1994                         case '\a':
1995                                 (void) fputc('a', fp);
1996                                 break;
1997
1998                         case '\b':
1999                                 (void) fputc('b', fp);
2000                                 break;
2001
2002                         case '\f':
2003                                 (void) fputc('f', fp);
2004                                 break;
2005
2006                         case '\n':
2007                                 (void) fputc('n', fp);
2008                                 break;
2009
2010                         case '\r':
2011                                 (void) fputc('r', fp);
2012                                 break;
2013
2014                         case '\t':
2015                                 (void) fputc('t', fp);
2016                                 break;
2017
2018                         case '\v':
2019                                 (void) fputc('v', fp);
2020                                 break;
2021
2022                         default:
2023                                 (void) fprintf(fp, "%.3o", c & 0377);
2024                                 break;
2025                         }
2026                 }
2027         }
2028 }
2029
2030 /*
2031  * eatsize(): Eat the size spec from a number [eg. 10UL]
2032  */
2033 private void
2034 eatsize(const char **p)
2035 {
2036         const char *l = *p;
2037
2038         if (LOWCASE(*l) == 'u') 
2039                 l++;
2040
2041         switch (LOWCASE(*l)) {
2042         case 'l':    /* long */
2043         case 's':    /* short */
2044         case 'h':    /* short */
2045         case 'b':    /* char/byte */
2046         case 'c':    /* char/byte */
2047                 l++;
2048                 /*FALLTHROUGH*/
2049         default:
2050                 break;
2051         }
2052
2053         *p = l;
2054 }
2055
2056 /*
2057  * handle a compiled file.
2058  */
2059 private int
2060 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
2061     const char *fn)
2062 {
2063         int fd;
2064         struct stat st;
2065         uint32_t *ptr;
2066         uint32_t version;
2067         int needsbyteswap;
2068         char *dbname = NULL;
2069         void *mm = NULL;
2070
2071         dbname = mkdbname(ms, fn, 0);
2072         if (dbname == NULL)
2073                 goto error2;
2074
2075         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2076                 goto error2;
2077
2078         if (fstat(fd, &st) == -1) {
2079                 file_error(ms, errno, "cannot stat `%s'", dbname);
2080                 goto error1;
2081         }
2082         if (st.st_size < 8) {
2083                 file_error(ms, 0, "file `%s' is too small", dbname);
2084                 goto error1;
2085         }
2086
2087 #ifdef QUICK
2088         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2089             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2090                 file_error(ms, errno, "cannot map `%s'", dbname);
2091                 goto error1;
2092         }
2093 #define RET     2
2094 #else
2095         if ((mm = CAST(void *, malloc((size_t)st.st_size))) == NULL) {
2096                 file_oomem(ms, (size_t)st.st_size);
2097                 goto error1;
2098         }
2099         if (read(fd, mm, (size_t)st.st_size) != (ssize_t)st.st_size) {
2100                 file_badread(ms);
2101                 goto error1;
2102         }
2103 #define RET     1
2104 #endif
2105         *magicp = CAST(struct magic *, mm);
2106         (void)close(fd);
2107         fd = -1;
2108         ptr = (uint32_t *)(void *)*magicp;
2109         if (*ptr != MAGICNO) {
2110                 if (swap4(*ptr) != MAGICNO) {
2111                         file_error(ms, 0, "bad magic in `%s'", dbname);
2112                         goto error1;
2113                 }
2114                 needsbyteswap = 1;
2115         } else
2116                 needsbyteswap = 0;
2117         if (needsbyteswap)
2118                 version = swap4(ptr[1]);
2119         else
2120                 version = ptr[1];
2121         if (version != VERSIONNO) {
2122                 file_error(ms, 0, "File %d.%d supports only version %d magic "
2123                     "files. `%s' is version %d", FILE_VERSION_MAJOR, patchlevel,
2124                     VERSIONNO, dbname, version);
2125                 goto error1;
2126         }
2127         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic));
2128         if (*nmagicp > 0)
2129                 (*nmagicp)--;
2130         (*magicp)++;
2131         if (needsbyteswap)
2132                 byteswap(*magicp, *nmagicp);
2133         free(dbname);
2134         return RET;
2135
2136 error1:
2137         if (fd != -1)
2138                 (void)close(fd);
2139         if (mm) {
2140 #ifdef QUICK
2141                 (void)munmap((void *)mm, (size_t)st.st_size);
2142 #else
2143                 free(mm);
2144 #endif
2145         } else {
2146                 *magicp = NULL;
2147                 *nmagicp = 0;
2148         }
2149 error2:
2150         free(dbname);
2151         return -1;
2152 }
2153
2154 private const uint32_t ar[] = {
2155     MAGICNO, VERSIONNO
2156 };
2157 /*
2158  * handle an mmaped file.
2159  */
2160 private int
2161 apprentice_compile(struct magic_set *ms, struct magic **magicp,
2162     uint32_t *nmagicp, const char *fn)
2163 {
2164         int fd;
2165         char *dbname;
2166         int rv = -1;
2167
2168         dbname = mkdbname(ms, fn, 1);
2169
2170         if (dbname == NULL) 
2171                 goto out;
2172
2173         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
2174                 file_error(ms, errno, "cannot open `%s'", dbname);
2175                 goto out;
2176         }
2177
2178         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
2179                 file_error(ms, errno, "error writing `%s'", dbname);
2180                 goto out;
2181         }
2182
2183         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
2184             != sizeof(struct magic)) {
2185                 file_error(ms, errno, "error seeking `%s'", dbname);
2186                 goto out;
2187         }
2188
2189         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
2190             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
2191                 file_error(ms, errno, "error writing `%s'", dbname);
2192                 goto out;
2193         }
2194
2195         (void)close(fd);
2196         rv = 0;
2197 out:
2198         free(dbname);
2199         return rv;
2200 }
2201
2202 private const char ext[] = ".mgc";
2203 /*
2204  * make a dbname
2205  */
2206 private char *
2207 mkdbname(struct magic_set *ms, const char *fn, int strip)
2208 {
2209         const char *p, *q;
2210         char *buf;
2211
2212         if (strip) {
2213                 if ((p = strrchr(fn, '/')) != NULL)
2214                         fn = ++p;
2215         }
2216
2217         for (q = fn; *q; q++)
2218                 continue;
2219         /* Look for .mgc */
2220         for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
2221                 if (*p != *q)
2222                         break;
2223
2224         /* Did not find .mgc, restore q */
2225         if (p >= ext)
2226                 while (*q)
2227                         q++;
2228
2229         q++;
2230         /* Compatibility with old code that looked in .mime */
2231         if (ms->flags & MAGIC_MIME) {
2232                 asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext);
2233                 if (access(buf, R_OK) != -1) {
2234                         ms->flags &= MAGIC_MIME_TYPE;
2235                         return buf;
2236                 }
2237                 free(buf);
2238         }
2239         asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext);
2240
2241         /* Compatibility with old code that looked in .mime */
2242         if (strstr(p, ".mime") != NULL)
2243                 ms->flags &= MAGIC_MIME_TYPE;
2244         return buf;
2245 }
2246
2247 /*
2248  * Byteswap an mmap'ed file if needed
2249  */
2250 private void
2251 byteswap(struct magic *magic, uint32_t nmagic)
2252 {
2253         uint32_t i;
2254         for (i = 0; i < nmagic; i++)
2255                 bs1(&magic[i]);
2256 }
2257
2258 /*
2259  * swap a short
2260  */
2261 private uint16_t
2262 swap2(uint16_t sv)
2263 {
2264         uint16_t rv;
2265         uint8_t *s = (uint8_t *)(void *)&sv; 
2266         uint8_t *d = (uint8_t *)(void *)&rv; 
2267         d[0] = s[1];
2268         d[1] = s[0];
2269         return rv;
2270 }
2271
2272 /*
2273  * swap an int
2274  */
2275 private uint32_t
2276 swap4(uint32_t sv)
2277 {
2278         uint32_t rv;
2279         uint8_t *s = (uint8_t *)(void *)&sv; 
2280         uint8_t *d = (uint8_t *)(void *)&rv; 
2281         d[0] = s[3];
2282         d[1] = s[2];
2283         d[2] = s[1];
2284         d[3] = s[0];
2285         return rv;
2286 }
2287
2288 /*
2289  * swap a quad
2290  */
2291 private uint64_t
2292 swap8(uint64_t sv)
2293 {
2294         uint64_t rv;
2295         uint8_t *s = (uint8_t *)(void *)&sv; 
2296         uint8_t *d = (uint8_t *)(void *)&rv; 
2297 #if 0
2298         d[0] = s[3];
2299         d[1] = s[2];
2300         d[2] = s[1];
2301         d[3] = s[0];
2302         d[4] = s[7];
2303         d[5] = s[6];
2304         d[6] = s[5];
2305         d[7] = s[4];
2306 #else
2307         d[0] = s[7];
2308         d[1] = s[6];
2309         d[2] = s[5];
2310         d[3] = s[4];
2311         d[4] = s[3];
2312         d[5] = s[2];
2313         d[6] = s[1];
2314         d[7] = s[0];
2315 #endif
2316         return rv;
2317 }
2318
2319 /*
2320  * byteswap a single magic entry
2321  */
2322 private void
2323 bs1(struct magic *m)
2324 {
2325         m->cont_level = swap2(m->cont_level);
2326         m->offset = swap4((uint32_t)m->offset);
2327         m->in_offset = swap4((uint32_t)m->in_offset);
2328         m->lineno = swap4((uint32_t)m->lineno);
2329         if (IS_STRING(m->type)) {
2330                 m->str_range = swap4(m->str_range);
2331                 m->str_flags = swap4(m->str_flags);
2332         }
2333         else {
2334                 m->value.q = swap8(m->value.q);
2335                 m->num_mask = swap8(m->num_mask);
2336         }
2337 }