]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/file/src/apprentice.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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.233 2015/06/10 00:57:41 christos Exp $")
36 #endif  /* lint */
37
38 #include "magic.h"
39 #include <stdlib.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #ifdef HAVE_STDDEF_H
44 #include <stddef.h>
45 #endif
46 #include <string.h>
47 #include <assert.h>
48 #include <ctype.h>
49 #include <fcntl.h>
50 #ifdef QUICK
51 #include <sys/mman.h>
52 #endif
53 #include <dirent.h>
54 #if defined(HAVE_LIMITS_H)
55 #include <limits.h>
56 #endif
57
58 #ifndef SSIZE_MAX
59 #define MAXMAGIC_SIZE        ((ssize_t)0x7fffffff)
60 #else
61 #define MAXMAGIC_SIZE        SSIZE_MAX
62 #endif
63
64 #define EATAB {while (isascii((unsigned char) *l) && \
65                       isspace((unsigned char) *l))  ++l;}
66 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
67                         tolower((unsigned char) (l)) : (l))
68 /*
69  * Work around a bug in headers on Digital Unix.
70  * At least confirmed for: OSF1 V4.0 878
71  */
72 #if defined(__osf__) && defined(__DECC)
73 #ifdef MAP_FAILED
74 #undef MAP_FAILED
75 #endif
76 #endif
77
78 #ifndef MAP_FAILED
79 #define MAP_FAILED (void *) -1
80 #endif
81
82 #ifndef MAP_FILE
83 #define MAP_FILE 0
84 #endif
85
86 #define ALLOC_CHUNK     (size_t)10
87 #define ALLOC_INCR      (size_t)200
88
89 #define MAP_TYPE_MMAP   0
90 #define MAP_TYPE_MALLOC 1
91 #define MAP_TYPE_USER   2
92
93 struct magic_entry {
94         struct magic *mp;       
95         uint32_t cont_count;
96         uint32_t max_count;
97 };
98
99 struct magic_entry_set {
100         struct magic_entry *me;
101         uint32_t count;
102         uint32_t max;
103 };
104
105 struct magic_map {
106         void *p;
107         size_t len;
108         int type;
109         struct magic *magic[MAGIC_SETS];
110         uint32_t nmagic[MAGIC_SETS];
111 };
112
113 int file_formats[FILE_NAMES_SIZE];
114 const size_t file_nformats = FILE_NAMES_SIZE;
115 const char *file_names[FILE_NAMES_SIZE];
116 const size_t file_nnames = FILE_NAMES_SIZE;
117
118 private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
119 private int hextoint(int);
120 private const char *getstr(struct magic_set *, struct magic *, const char *,
121     int);
122 private int parse(struct magic_set *, struct magic_entry *, const char *,
123     size_t, int);
124 private void eatsize(const char **);
125 private int apprentice_1(struct magic_set *, const char *, int);
126 private size_t apprentice_magic_strength(const struct magic *);
127 private int apprentice_sort(const void *, const void *);
128 private void apprentice_list(struct mlist *, int );
129 private struct magic_map *apprentice_load(struct magic_set *, 
130     const char *, int);
131 private struct mlist *mlist_alloc(void);
132 private void mlist_free(struct mlist *);
133 private void byteswap(struct magic *, uint32_t);
134 private void bs1(struct magic *);
135 private uint16_t swap2(uint16_t);
136 private uint32_t swap4(uint32_t);
137 private uint64_t swap8(uint64_t);
138 private char *mkdbname(struct magic_set *, const char *, int);
139 private struct magic_map *apprentice_buf(struct magic_set *, struct magic *,
140     size_t);
141 private struct magic_map *apprentice_map(struct magic_set *, const char *);
142 private int check_buffer(struct magic_set *, struct magic_map *, const char *);
143 private void apprentice_unmap(struct magic_map *);
144 private int apprentice_compile(struct magic_set *, struct magic_map *,
145     const char *);
146 private int check_format_type(const char *, int);
147 private int check_format(struct magic_set *, struct magic *);
148 private int get_op(char);
149 private int parse_mime(struct magic_set *, struct magic_entry *, const char *);
150 private int parse_strength(struct magic_set *, struct magic_entry *, const char *);
151 private int parse_apple(struct magic_set *, struct magic_entry *, const char *);
152 private int parse_ext(struct magic_set *, struct magic_entry *, const char *);
153
154
155 private size_t magicsize = sizeof(struct magic);
156
157 private const char usg_hdr[] = "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
158
159 private struct {
160         const char *name;
161         size_t len;
162         int (*fun)(struct magic_set *, struct magic_entry *, const char *);
163 } bang[] = {
164 #define DECLARE_FIELD(name) { # name, sizeof(# name) - 1, parse_ ## name }
165         DECLARE_FIELD(mime),
166         DECLARE_FIELD(apple),
167         DECLARE_FIELD(ext),
168         DECLARE_FIELD(strength),
169 #undef  DECLARE_FIELD
170         { NULL, 0, NULL }
171 };
172
173 #ifdef COMPILE_ONLY
174
175 int main(int, char *[]);
176
177 int
178 main(int argc, char *argv[])
179 {
180         int ret;
181         struct magic_set *ms;
182         char *progname;
183
184         if ((progname = strrchr(argv[0], '/')) != NULL)
185                 progname++;
186         else
187                 progname = argv[0];
188
189         if (argc != 2) {
190                 (void)fprintf(stderr, "Usage: %s file\n", progname);
191                 return 1;
192         }
193
194         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
195                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
196                 return 1;
197         }
198         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
199         if (ret == 1)
200                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
201         magic_close(ms);
202         return ret;
203 }
204 #endif /* COMPILE_ONLY */
205
206 struct type_tbl_s {
207         const char name[16];
208         const size_t len;
209         const int type;
210         const int format;
211 };
212
213 /*
214  * XXX - the actual Single UNIX Specification says that "long" means "long",
215  * as in the C data type, but we treat it as meaning "4-byte integer".
216  * Given that the OS X version of file 5.04 did the same, I guess that passes
217  * the actual test; having "long" be dependent on how big a "long" is on
218  * the machine running "file" is silly.
219  */
220 static const struct type_tbl_s type_tbl[] = {
221 # define XX(s)          s, (sizeof(s) - 1)
222 # define XX_NULL        "", 0
223         { XX("invalid"),        FILE_INVALID,           FILE_FMT_NONE },
224         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
225         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
226         { XX("default"),        FILE_DEFAULT,           FILE_FMT_NONE },
227         { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
228         { XX("string"),         FILE_STRING,            FILE_FMT_STR },
229         { XX("date"),           FILE_DATE,              FILE_FMT_STR },
230         { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
231         { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
232         { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
233         { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
234         { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
235         { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
236         { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
237         { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
238         { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
239         { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
240         { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
241         { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
242         { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
243         { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
244         { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
245         { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
246         { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
247         { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
248         { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
249         { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
250         { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
251         { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
252         { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
253         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
254         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
255         { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
256         { XX("float"),          FILE_FLOAT,             FILE_FMT_FLOAT },
257         { XX("befloat"),        FILE_BEFLOAT,           FILE_FMT_FLOAT },
258         { XX("lefloat"),        FILE_LEFLOAT,           FILE_FMT_FLOAT },
259         { XX("double"),         FILE_DOUBLE,            FILE_FMT_DOUBLE },
260         { XX("bedouble"),       FILE_BEDOUBLE,          FILE_FMT_DOUBLE },
261         { XX("ledouble"),       FILE_LEDOUBLE,          FILE_FMT_DOUBLE },
262         { XX("leid3"),          FILE_LEID3,             FILE_FMT_NUM },
263         { XX("beid3"),          FILE_BEID3,             FILE_FMT_NUM },
264         { XX("indirect"),       FILE_INDIRECT,          FILE_FMT_NUM },
265         { XX("qwdate"),         FILE_QWDATE,            FILE_FMT_STR },
266         { XX("leqwdate"),       FILE_LEQWDATE,          FILE_FMT_STR },
267         { XX("beqwdate"),       FILE_BEQWDATE,          FILE_FMT_STR },
268         { XX("name"),           FILE_NAME,              FILE_FMT_NONE },
269         { XX("use"),            FILE_USE,               FILE_FMT_NONE },
270         { XX("clear"),          FILE_CLEAR,             FILE_FMT_NONE },
271         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
272 };
273
274 /*
275  * These are not types, and cannot be preceded by "u" to make them
276  * unsigned.
277  */
278 static const struct type_tbl_s special_tbl[] = {
279         { XX("name"),           FILE_NAME,              FILE_FMT_STR },
280         { XX("use"),            FILE_USE,               FILE_FMT_STR },
281         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
282 };
283 # undef XX
284 # undef XX_NULL
285
286 private int
287 get_type(const struct type_tbl_s *tbl, const char *l, const char **t)
288 {
289         const struct type_tbl_s *p;
290
291         for (p = tbl; p->len; p++) {
292                 if (strncmp(l, p->name, p->len) == 0) {
293                         if (t)
294                                 *t = l + p->len;
295                         break;
296                 }
297         }
298         return p->type;
299 }
300
301 private int
302 get_standard_integer_type(const char *l, const char **t)
303 {
304         int type;
305
306         if (isalpha((unsigned char)l[1])) {
307                 switch (l[1]) {
308                 case 'C':
309                         /* "dC" and "uC" */
310                         type = FILE_BYTE;
311                         break;
312                 case 'S':
313                         /* "dS" and "uS" */
314                         type = FILE_SHORT;
315                         break;
316                 case 'I':
317                 case 'L':
318                         /*
319                          * "dI", "dL", "uI", and "uL".
320                          *
321                          * XXX - the actual Single UNIX Specification says
322                          * that "L" means "long", as in the C data type,
323                          * but we treat it as meaning "4-byte integer".
324                          * Given that the OS X version of file 5.04 did
325                          * the same, I guess that passes the actual SUS
326                          * validation suite; having "dL" be dependent on
327                          * how big a "long" is on the machine running
328                          * "file" is silly.
329                          */
330                         type = FILE_LONG;
331                         break;
332                 case 'Q':
333                         /* "dQ" and "uQ" */
334                         type = FILE_QUAD;
335                         break;
336                 default:
337                         /* "d{anything else}", "u{anything else}" */
338                         return FILE_INVALID;
339                 }
340                 l += 2;
341         } else if (isdigit((unsigned char)l[1])) {
342                 /*
343                  * "d{num}" and "u{num}"; we only support {num} values
344                  * of 1, 2, 4, and 8 - the Single UNIX Specification
345                  * doesn't say anything about whether arbitrary
346                  * values should be supported, but both the Solaris 10
347                  * and OS X Mountain Lion versions of file passed the
348                  * Single UNIX Specification validation suite, and
349                  * neither of them support values bigger than 8 or
350                  * non-power-of-2 values.
351                  */
352                 if (isdigit((unsigned char)l[2])) {
353                         /* Multi-digit, so > 9 */
354                         return FILE_INVALID;
355                 }
356                 switch (l[1]) {
357                 case '1':
358                         type = FILE_BYTE;
359                         break;
360                 case '2':
361                         type = FILE_SHORT;
362                         break;
363                 case '4':
364                         type = FILE_LONG;
365                         break;
366                 case '8':
367                         type = FILE_QUAD;
368                         break;
369                 default:
370                         /* XXX - what about 3, 5, 6, or 7? */
371                         return FILE_INVALID;
372                 }
373                 l += 2;
374         } else {
375                 /*
376                  * "d" or "u" by itself.
377                  */
378                 type = FILE_LONG;
379                 ++l;
380         }
381         if (t)
382                 *t = l;
383         return type;
384 }
385
386 private void
387 init_file_tables(void)
388 {
389         static int done = 0;
390         const struct type_tbl_s *p;
391
392         if (done)
393                 return;
394         done++;
395
396         for (p = type_tbl; p->len; p++) {
397                 assert(p->type < FILE_NAMES_SIZE);
398                 file_names[p->type] = p->name;
399                 file_formats[p->type] = p->format;
400         }
401         assert(p - type_tbl == FILE_NAMES_SIZE);
402 }
403
404 private int
405 add_mlist(struct mlist *mlp, struct magic_map *map, size_t idx)
406 {
407         struct mlist *ml;
408
409         mlp->map = idx == 0 ? map : NULL;
410         if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL)
411                 return -1;
412
413         ml->map = NULL;
414         ml->magic = map->magic[idx];
415         ml->nmagic = map->nmagic[idx];
416
417         mlp->prev->next = ml;
418         ml->prev = mlp->prev;
419         ml->next = mlp;
420         mlp->prev = ml;
421         return 0;
422 }
423
424 /*
425  * Handle one file or directory.
426  */
427 private int
428 apprentice_1(struct magic_set *ms, const char *fn, int action)
429 {
430         struct magic_map *map;
431 #ifndef COMPILE_ONLY
432         struct mlist *ml;
433         size_t i;
434 #endif
435
436         if (magicsize != FILE_MAGICSIZE) {
437                 file_error(ms, 0, "magic element size %lu != %lu",
438                     (unsigned long)sizeof(*map->magic[0]),
439                     (unsigned long)FILE_MAGICSIZE);
440                 return -1;
441         }
442
443         if (action == FILE_COMPILE) {
444                 map = apprentice_load(ms, fn, action);
445                 if (map == NULL)
446                         return -1;
447                 return apprentice_compile(ms, map, fn);
448         }
449
450 #ifndef COMPILE_ONLY
451         map = apprentice_map(ms, fn);
452         if (map == NULL) {
453                 if (ms->flags & MAGIC_CHECK)
454                         file_magwarn(ms, "using regular magic file `%s'", fn);
455                 map = apprentice_load(ms, fn, action);
456                 if (map == NULL)
457                         return -1;
458         }
459
460         for (i = 0; i < MAGIC_SETS; i++) {
461                 if (add_mlist(ms->mlist[i], map, i) == -1) {
462                         file_oomem(ms, sizeof(*ml));
463                         goto fail;
464                 }
465         }
466
467         if (action == FILE_LIST) {
468                 for (i = 0; i < MAGIC_SETS; i++) {
469                         printf("Set %" SIZE_T_FORMAT "u:\nBinary patterns:\n",
470                             i);
471                         apprentice_list(ms->mlist[i], BINTEST);
472                         printf("Text patterns:\n");
473                         apprentice_list(ms->mlist[i], TEXTTEST);
474                 }
475         }
476         return 0;
477 fail:
478         for (i = 0; i < MAGIC_SETS; i++) {
479                 mlist_free(ms->mlist[i]);
480                 ms->mlist[i] = NULL;
481         }
482         return -1;
483 #else
484         return 0;
485 #endif /* COMPILE_ONLY */
486 }
487
488 protected void
489 file_ms_free(struct magic_set *ms)
490 {
491         size_t i;
492         if (ms == NULL)
493                 return;
494         for (i = 0; i < MAGIC_SETS; i++)
495                 mlist_free(ms->mlist[i]);
496         free(ms->o.pbuf);
497         free(ms->o.buf);
498         free(ms->c.li);
499         free(ms);
500 }
501
502 protected struct magic_set *
503 file_ms_alloc(int flags)
504 {
505         struct magic_set *ms;
506         size_t i, len;
507
508         if ((ms = CAST(struct magic_set *, calloc((size_t)1,
509             sizeof(struct magic_set)))) == NULL)
510                 return NULL;
511
512         if (magic_setflags(ms, flags) == -1) {
513                 errno = EINVAL;
514                 goto free;
515         }
516
517         ms->o.buf = ms->o.pbuf = NULL;
518         len = (ms->c.len = 10) * sizeof(*ms->c.li);
519
520         if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL)
521                 goto free;
522
523         ms->event_flags = 0;
524         ms->error = -1;
525         for (i = 0; i < MAGIC_SETS; i++)
526                 ms->mlist[i] = NULL;
527         ms->file = "unknown";
528         ms->line = 0;
529         ms->indir_max = FILE_INDIR_MAX;
530         ms->name_max = FILE_NAME_MAX;
531         ms->elf_shnum_max = FILE_ELF_SHNUM_MAX;
532         ms->elf_phnum_max = FILE_ELF_PHNUM_MAX;
533         ms->elf_notes_max = FILE_ELF_NOTES_MAX;
534         return ms;
535 free:
536         free(ms);
537         return NULL;
538 }
539
540 private void
541 apprentice_unmap(struct magic_map *map)
542 {
543         if (map == NULL)
544                 return;
545
546         switch (map->type) {
547 #ifdef QUICK
548         case MAP_TYPE_MMAP:
549                 if (map->p)
550                         (void)munmap(map->p, map->len);
551                 break;
552 #endif
553         case MAP_TYPE_MALLOC:
554                 free(map->p);
555                 break;
556         case MAP_TYPE_USER:
557                 break;
558         default:
559                 abort();
560         }
561         free(map);
562 }
563
564 private struct mlist *
565 mlist_alloc(void)
566 {
567         struct mlist *mlist;
568         if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) {
569                 return NULL;
570         }
571         mlist->next = mlist->prev = mlist;
572         return mlist;
573 }
574
575 private void
576 mlist_free(struct mlist *mlist)
577 {
578         struct mlist *ml, *next;
579
580         if (mlist == NULL)
581                 return;
582
583         ml = mlist->next;
584         for (ml = mlist->next; (next = ml->next) != NULL; ml = next) {
585                 if (ml->map)
586                         apprentice_unmap(ml->map);
587                 free(ml);
588                 if (ml == mlist)
589                         break;
590         }
591 }
592
593 #ifndef COMPILE_ONLY
594 /* void **bufs: an array of compiled magic files */
595 protected int
596 buffer_apprentice(struct magic_set *ms, struct magic **bufs,
597     size_t *sizes, size_t nbufs)
598 {
599         size_t i, j;
600         struct mlist *ml;
601         struct magic_map *map;
602
603         if (nbufs == 0)
604                 return -1;
605
606         if (ms->mlist[0] != NULL)
607                 file_reset(ms);
608
609         init_file_tables();
610
611         for (i = 0; i < MAGIC_SETS; i++) {
612                 mlist_free(ms->mlist[i]);
613                 if ((ms->mlist[i] = mlist_alloc()) == NULL) {
614                         file_oomem(ms, sizeof(*ms->mlist[i]));
615                         goto fail;
616                 }
617         }
618
619         for (i = 0; i < nbufs; i++) {
620                 map = apprentice_buf(ms, bufs[i], sizes[i]);
621                 if (map == NULL)
622                         goto fail;
623
624                 for (j = 0; j < MAGIC_SETS; j++) {
625                         if (add_mlist(ms->mlist[j], map, j) == -1) {
626                                 file_oomem(ms, sizeof(*ml));
627                                 goto fail;
628                         }
629                 }
630         }
631
632         return 0;
633 fail:
634         for (i = 0; i < MAGIC_SETS; i++) {
635                 mlist_free(ms->mlist[i]);
636                 ms->mlist[i] = NULL;
637         }
638         return -1;
639 }
640 #endif
641
642 /* const char *fn: list of magic files and directories */
643 protected int
644 file_apprentice(struct magic_set *ms, const char *fn, int action)
645 {
646         char *p, *mfn;
647         int file_err, errs = -1;
648         size_t i;
649
650         if (ms->mlist[0] != NULL)
651                 file_reset(ms);
652
653         if ((fn = magic_getpath(fn, action)) == NULL)
654                 return -1;
655
656         init_file_tables();
657
658         if ((mfn = strdup(fn)) == NULL) {
659                 file_oomem(ms, strlen(fn));
660                 return -1;
661         }
662
663         for (i = 0; i < MAGIC_SETS; i++) {
664                 mlist_free(ms->mlist[i]);
665                 if ((ms->mlist[i] = mlist_alloc()) == NULL) {
666                         file_oomem(ms, sizeof(*ms->mlist[i]));
667                         while (i-- > 0) {
668                                 mlist_free(ms->mlist[i]);
669                                 ms->mlist[i] = NULL;
670                         }
671                         free(mfn);
672                         return -1;
673                 }
674         }
675         fn = mfn;
676
677         while (fn) {
678                 p = strchr(fn, PATHSEP);
679                 if (p)
680                         *p++ = '\0';
681                 if (*fn == '\0')
682                         break;
683                 file_err = apprentice_1(ms, fn, action);
684                 errs = MAX(errs, file_err);
685                 fn = p;
686         }
687
688         free(mfn);
689
690         if (errs == -1) {
691                 for (i = 0; i < MAGIC_SETS; i++) {
692                         mlist_free(ms->mlist[i]);
693                         ms->mlist[i] = NULL;
694                 }
695                 file_error(ms, 0, "could not find any valid magic files!");
696                 return -1;
697         }
698
699 #if 0
700         /*
701          * Always leave the database loaded
702          */
703         if (action == FILE_LOAD)
704                 return 0;
705
706         for (i = 0; i < MAGIC_SETS; i++) {
707                 mlist_free(ms->mlist[i]);
708                 ms->mlist[i] = NULL;
709         }
710 #endif
711
712         switch (action) {
713         case FILE_LOAD:
714         case FILE_COMPILE:
715         case FILE_CHECK:
716         case FILE_LIST:
717                 return 0;
718         default:
719                 file_error(ms, 0, "Invalid action %d", action);
720                 return -1;
721         }
722 }
723
724 /*
725  * Compute the real length of a magic expression, for the purposes
726  * of determining how "strong" a magic expression is (approximating
727  * how specific its matches are):
728  *      - magic characters count 0 unless escaped.
729  *      - [] expressions count 1
730  *      - {} expressions count 0
731  *      - regular characters or escaped magic characters count 1
732  *      - 0 length expressions count as one
733  */
734 private size_t
735 nonmagic(const char *str)
736 {
737         const char *p;
738         size_t rv = 0;
739
740         for (p = str; *p; p++)
741                 switch (*p) {
742                 case '\\':      /* Escaped anything counts 1 */
743                         if (!*++p)
744                                 p--;
745                         rv++;
746                         continue;
747                 case '?':       /* Magic characters count 0 */
748                 case '*':
749                 case '.':
750                 case '+':
751                 case '^':
752                 case '$':
753                         continue;
754                 case '[':       /* Bracketed expressions count 1 the ']' */
755                         while (*p && *p != ']')
756                                 p++;
757                         p--;
758                         continue;
759                 case '{':       /* Braced expressions count 0 */
760                         while (*p && *p != '}')
761                                 p++;
762                         if (!*p)
763                                 p--;
764                         continue;
765                 default:        /* Anything else counts 1 */
766                         rv++;
767                         continue;
768                 }
769
770         return rv == 0 ? 1 : rv;        /* Return at least 1 */
771 }
772
773 /*
774  * Get weight of this magic entry, for sorting purposes.
775  */
776 private size_t
777 apprentice_magic_strength(const struct magic *m)
778 {
779 #define MULT 10
780         size_t v, val = 2 * MULT;       /* baseline strength */
781
782         switch (m->type) {
783         case FILE_DEFAULT:      /* make sure this sorts last */
784                 if (m->factor_op != FILE_FACTOR_OP_NONE)
785                         abort();
786                 return 0;
787
788         case FILE_BYTE:
789                 val += 1 * MULT;
790                 break;
791
792         case FILE_SHORT:
793         case FILE_LESHORT:
794         case FILE_BESHORT:
795                 val += 2 * MULT;
796                 break;
797
798         case FILE_LONG:
799         case FILE_LELONG:
800         case FILE_BELONG:
801         case FILE_MELONG:
802                 val += 4 * MULT;
803                 break;
804
805         case FILE_PSTRING:
806         case FILE_STRING:
807                 val += m->vallen * MULT;
808                 break;
809
810         case FILE_BESTRING16:
811         case FILE_LESTRING16:
812                 val += m->vallen * MULT / 2;
813                 break;
814
815         case FILE_SEARCH:
816                 val += m->vallen * MAX(MULT / m->vallen, 1);
817                 break;
818
819         case FILE_REGEX:
820                 v = nonmagic(m->value.s);
821                 val += v * MAX(MULT / v, 1);
822                 break;
823
824         case FILE_DATE:
825         case FILE_LEDATE:
826         case FILE_BEDATE:
827         case FILE_MEDATE:
828         case FILE_LDATE:
829         case FILE_LELDATE:
830         case FILE_BELDATE:
831         case FILE_MELDATE:
832         case FILE_FLOAT:
833         case FILE_BEFLOAT:
834         case FILE_LEFLOAT:
835                 val += 4 * MULT;
836                 break;
837
838         case FILE_QUAD:
839         case FILE_BEQUAD:
840         case FILE_LEQUAD:
841         case FILE_QDATE:
842         case FILE_LEQDATE:
843         case FILE_BEQDATE:
844         case FILE_QLDATE:
845         case FILE_LEQLDATE:
846         case FILE_BEQLDATE:
847         case FILE_QWDATE:
848         case FILE_LEQWDATE:
849         case FILE_BEQWDATE:
850         case FILE_DOUBLE:
851         case FILE_BEDOUBLE:
852         case FILE_LEDOUBLE:
853                 val += 8 * MULT;
854                 break;
855
856         case FILE_INDIRECT:
857         case FILE_NAME:
858         case FILE_USE:
859                 break;
860
861         default:
862                 (void)fprintf(stderr, "Bad type %d\n", m->type);
863                 abort();
864         }
865
866         switch (m->reln) {
867         case 'x':       /* matches anything penalize */
868         case '!':       /* matches almost anything penalize */
869                 val = 0;
870                 break;
871
872         case '=':       /* Exact match, prefer */
873                 val += MULT;
874                 break;
875
876         case '>':
877         case '<':       /* comparison match reduce strength */
878                 val -= 2 * MULT;
879                 break;
880
881         case '^':
882         case '&':       /* masking bits, we could count them too */
883                 val -= MULT;
884                 break;
885
886         default:
887                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
888                 abort();
889         }
890
891         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
892                 val = 1;
893
894         switch (m->factor_op) {
895         case FILE_FACTOR_OP_NONE:
896                 break;
897         case FILE_FACTOR_OP_PLUS:
898                 val += m->factor;
899                 break;
900         case FILE_FACTOR_OP_MINUS:
901                 val -= m->factor;
902                 break;
903         case FILE_FACTOR_OP_TIMES:
904                 val *= m->factor;
905                 break;
906         case FILE_FACTOR_OP_DIV:
907                 val /= m->factor;
908                 break;
909         default:
910                 abort();
911         }
912
913         /*
914          * Magic entries with no description get a bonus because they depend
915          * on subsequent magic entries to print something.
916          */
917         if (m->desc[0] == '\0')
918                 val++;
919         return val;
920 }
921
922 /*  
923  * Sort callback for sorting entries by "strength" (basically length)
924  */
925 private int
926 apprentice_sort(const void *a, const void *b)
927 {
928         const struct magic_entry *ma = CAST(const struct magic_entry *, a);
929         const struct magic_entry *mb = CAST(const struct magic_entry *, b);
930         size_t sa = apprentice_magic_strength(ma->mp);
931         size_t sb = apprentice_magic_strength(mb->mp);
932         if (sa == sb)
933                 return 0;
934         else if (sa > sb)
935                 return -1;
936         else
937                 return 1;
938 }
939
940 /*  
941  * Shows sorted patterns list in the order which is used for the matching
942  */
943 private void
944 apprentice_list(struct mlist *mlist, int mode)
945 {
946         uint32_t magindex = 0;
947         struct mlist *ml;
948         for (ml = mlist->next; ml != mlist; ml = ml->next) {
949                 for (magindex = 0; magindex < ml->nmagic; magindex++) {
950                         struct magic *m = &ml->magic[magindex];
951                         if ((m->flag & mode) != mode) {
952                                 /* Skip sub-tests */
953                                 while (magindex + 1 < ml->nmagic &&
954                                        ml->magic[magindex + 1].cont_level != 0)
955                                         ++magindex;
956                                 continue; /* Skip to next top-level test*/
957                         }
958
959                         /*
960                          * Try to iterate over the tree until we find item with
961                          * description/mimetype.
962                          */
963                         while (magindex + 1 < ml->nmagic &&
964                                ml->magic[magindex + 1].cont_level != 0 &&
965                                *ml->magic[magindex].desc == '\0' &&
966                                *ml->magic[magindex].mimetype == '\0')
967                                 magindex++;
968
969                         printf("Strength = %3" SIZE_T_FORMAT "u@%u: %s [%s]\n",
970                             apprentice_magic_strength(m),
971                             ml->magic[magindex].lineno,
972                             ml->magic[magindex].desc,
973                             ml->magic[magindex].mimetype);
974                 }
975         }
976 }
977
978 private void
979 set_test_type(struct magic *mstart, struct magic *m)
980 {
981         switch (m->type) {
982         case FILE_BYTE:
983         case FILE_SHORT:
984         case FILE_LONG:
985         case FILE_DATE:
986         case FILE_BESHORT:
987         case FILE_BELONG:
988         case FILE_BEDATE:
989         case FILE_LESHORT:
990         case FILE_LELONG:
991         case FILE_LEDATE:
992         case FILE_LDATE:
993         case FILE_BELDATE:
994         case FILE_LELDATE:
995         case FILE_MEDATE:
996         case FILE_MELDATE:
997         case FILE_MELONG:
998         case FILE_QUAD:
999         case FILE_LEQUAD:
1000         case FILE_BEQUAD:
1001         case FILE_QDATE:
1002         case FILE_LEQDATE:
1003         case FILE_BEQDATE:
1004         case FILE_QLDATE:
1005         case FILE_LEQLDATE:
1006         case FILE_BEQLDATE:
1007         case FILE_QWDATE:
1008         case FILE_LEQWDATE:
1009         case FILE_BEQWDATE:
1010         case FILE_FLOAT:
1011         case FILE_BEFLOAT:
1012         case FILE_LEFLOAT:
1013         case FILE_DOUBLE:
1014         case FILE_BEDOUBLE:
1015         case FILE_LEDOUBLE:
1016                 mstart->flag |= BINTEST;
1017                 break;
1018         case FILE_STRING:
1019         case FILE_PSTRING:
1020         case FILE_BESTRING16:
1021         case FILE_LESTRING16:
1022                 /* Allow text overrides */
1023                 if (mstart->str_flags & STRING_TEXTTEST)
1024                         mstart->flag |= TEXTTEST;
1025                 else
1026                         mstart->flag |= BINTEST;
1027                 break;
1028         case FILE_REGEX:
1029         case FILE_SEARCH:
1030                 /* Check for override */
1031                 if (mstart->str_flags & STRING_BINTEST)
1032                         mstart->flag |= BINTEST;
1033                 if (mstart->str_flags & STRING_TEXTTEST)
1034                         mstart->flag |= TEXTTEST;
1035                     
1036                 if (mstart->flag & (TEXTTEST|BINTEST))
1037                         break;
1038
1039                 /* binary test if pattern is not text */
1040                 if (file_looks_utf8(m->value.us, (size_t)m->vallen, NULL,
1041                     NULL) <= 0)
1042                         mstart->flag |= BINTEST;
1043                 else
1044                         mstart->flag |= TEXTTEST;
1045                 break;
1046         case FILE_DEFAULT:
1047                 /* can't deduce anything; we shouldn't see this at the
1048                    top level anyway */
1049                 break;
1050         case FILE_INVALID:
1051         default:
1052                 /* invalid search type, but no need to complain here */
1053                 break;
1054         }
1055 }
1056
1057 private int
1058 addentry(struct magic_set *ms, struct magic_entry *me,
1059    struct magic_entry_set *mset)
1060 {
1061         size_t i = me->mp->type == FILE_NAME ? 1 : 0;
1062         if (mset[i].count == mset[i].max) {
1063                 struct magic_entry *mp;
1064
1065                 mset[i].max += ALLOC_INCR;
1066                 if ((mp = CAST(struct magic_entry *,
1067                     realloc(mset[i].me, sizeof(*mp) * mset[i].max))) ==
1068                     NULL) {
1069                         file_oomem(ms, sizeof(*mp) * mset[i].max);
1070                         return -1;
1071                 }
1072                 (void)memset(&mp[mset[i].count], 0, sizeof(*mp) *
1073                     ALLOC_INCR);
1074                 mset[i].me = mp;
1075         }
1076         mset[i].me[mset[i].count++] = *me;
1077         memset(me, 0, sizeof(*me));
1078         return 0;
1079 }
1080
1081 /*
1082  * Load and parse one file.
1083  */
1084 private void
1085 load_1(struct magic_set *ms, int action, const char *fn, int *errs,
1086    struct magic_entry_set *mset)
1087 {
1088         size_t lineno = 0, llen = 0;
1089         char *line = NULL;
1090         ssize_t len;
1091         struct magic_entry me;
1092
1093         FILE *f = fopen(ms->file = fn, "r");
1094         if (f == NULL) {
1095                 if (errno != ENOENT)
1096                         file_error(ms, errno, "cannot read magic file `%s'",
1097                                    fn);
1098                 (*errs)++;
1099                 return;
1100         }
1101
1102         memset(&me, 0, sizeof(me));
1103         /* read and parse this file */
1104         for (ms->line = 1; (len = getline(&line, &llen, f)) != -1;
1105             ms->line++) {
1106                 if (len == 0) /* null line, garbage, etc */
1107                         continue;
1108                 if (line[len - 1] == '\n') {
1109                         lineno++;
1110                         line[len - 1] = '\0'; /* delete newline */
1111                 }
1112                 switch (line[0]) {
1113                 case '\0':      /* empty, do not parse */
1114                 case '#':       /* comment, do not parse */
1115                         continue;
1116                 case '!':
1117                         if (line[1] == ':') {
1118                                 size_t i;
1119
1120                                 for (i = 0; bang[i].name != NULL; i++) {
1121                                         if ((size_t)(len - 2) > bang[i].len &&
1122                                             memcmp(bang[i].name, line + 2,
1123                                             bang[i].len) == 0)
1124                                                 break;
1125                                 }
1126                                 if (bang[i].name == NULL) {
1127                                         file_error(ms, 0,
1128                                             "Unknown !: entry `%s'", line);
1129                                         (*errs)++;
1130                                         continue;
1131                                 }
1132                                 if (me.mp == NULL) {
1133                                         file_error(ms, 0,
1134                                             "No current entry for :!%s type",
1135                                                 bang[i].name);
1136                                         (*errs)++;
1137                                         continue;
1138                                 }
1139                                 if ((*bang[i].fun)(ms, &me,
1140                                     line + bang[i].len + 2) != 0) {
1141                                         (*errs)++;
1142                                         continue;
1143                                 }
1144                                 continue;
1145                         }
1146                         /*FALLTHROUGH*/
1147                 default:
1148                 again:
1149                         switch (parse(ms, &me, line, lineno, action)) {
1150                         case 0:
1151                                 continue;
1152                         case 1:
1153                                 (void)addentry(ms, &me, mset);
1154                                 goto again;
1155                         default:
1156                                 (*errs)++;
1157                                 break;
1158                         }
1159                 }
1160         }
1161         if (me.mp)
1162                 (void)addentry(ms, &me, mset);
1163         free(line);
1164         (void)fclose(f);
1165 }
1166
1167 /*
1168  * parse a file or directory of files
1169  * const char *fn: name of magic file or directory
1170  */
1171 private int
1172 cmpstrp(const void *p1, const void *p2)
1173 {
1174         return strcmp(*(char *const *)p1, *(char *const *)p2);
1175 }
1176
1177
1178 private uint32_t
1179 set_text_binary(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
1180     uint32_t starttest)
1181 {
1182         static const char text[] = "text";
1183         static const char binary[] = "binary";
1184         static const size_t len = sizeof(text);
1185
1186         uint32_t i = starttest;
1187
1188         do {
1189                 set_test_type(me[starttest].mp, me[i].mp);
1190                 if ((ms->flags & MAGIC_DEBUG) == 0)
1191                         continue;
1192                 (void)fprintf(stderr, "%s%s%s: %s\n",
1193                     me[i].mp->mimetype,
1194                     me[i].mp->mimetype[0] == '\0' ? "" : "; ",
1195                     me[i].mp->desc[0] ? me[i].mp->desc : "(no description)",
1196                     me[i].mp->flag & BINTEST ? binary : text);
1197                 if (me[i].mp->flag & BINTEST) {
1198                         char *p = strstr(me[i].mp->desc, text);
1199                         if (p && (p == me[i].mp->desc ||
1200                             isspace((unsigned char)p[-1])) &&
1201                             (p + len - me[i].mp->desc == MAXstring
1202                             || (p[len] == '\0' ||
1203                             isspace((unsigned char)p[len]))))
1204                                 (void)fprintf(stderr, "*** Possible "
1205                                     "binary test for text type\n");
1206                 }
1207         } while (++i < nme && me[i].mp->cont_level != 0);
1208         return i;
1209 }
1210
1211 private void
1212 set_last_default(struct magic_set *ms, struct magic_entry *me, uint32_t nme)
1213 {
1214         uint32_t i;
1215         for (i = 0; i < nme; i++) {
1216                 if (me[i].mp->cont_level == 0 &&
1217                     me[i].mp->type == FILE_DEFAULT) {
1218                         while (++i < nme)
1219                                 if (me[i].mp->cont_level == 0)
1220                                         break;
1221                         if (i != nme) {
1222                                 /* XXX - Ugh! */
1223                                 ms->line = me[i].mp->lineno;
1224                                 file_magwarn(ms,
1225                                     "level 0 \"default\" did not sort last");
1226                         }
1227                         return;                                     
1228                 }
1229         }
1230 }
1231
1232 private int
1233 coalesce_entries(struct magic_set *ms, struct magic_entry *me, uint32_t nme,
1234     struct magic **ma, uint32_t *nma)
1235 {
1236         uint32_t i, mentrycount = 0;
1237         size_t slen;
1238
1239         for (i = 0; i < nme; i++)
1240                 mentrycount += me[i].cont_count;
1241
1242         slen = sizeof(**ma) * mentrycount;
1243         if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) {
1244                 file_oomem(ms, slen);
1245                 return -1;
1246         }
1247
1248         mentrycount = 0;
1249         for (i = 0; i < nme; i++) {
1250                 (void)memcpy(*ma + mentrycount, me[i].mp,
1251                     me[i].cont_count * sizeof(**ma));
1252                 mentrycount += me[i].cont_count;
1253         }
1254         *nma = mentrycount;
1255         return 0;
1256 }
1257
1258 private void
1259 magic_entry_free(struct magic_entry *me, uint32_t nme)
1260 {
1261         uint32_t i;
1262         if (me == NULL)
1263                 return;
1264         for (i = 0; i < nme; i++)
1265                 free(me[i].mp);
1266         free(me);
1267 }
1268
1269 private struct magic_map *
1270 apprentice_load(struct magic_set *ms, const char *fn, int action)
1271 {
1272         int errs = 0;
1273         uint32_t i, j;
1274         size_t files = 0, maxfiles = 0;
1275         char **filearr = NULL, *mfn;
1276         struct stat st;
1277         struct magic_map *map;
1278         struct magic_entry_set mset[MAGIC_SETS];
1279         DIR *dir;
1280         struct dirent *d;
1281
1282         memset(mset, 0, sizeof(mset));
1283         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
1284
1285
1286         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL)
1287         {
1288                 file_oomem(ms, sizeof(*map));
1289                 return NULL;
1290         }
1291
1292         /* print silly verbose header for USG compat. */
1293         if (action == FILE_CHECK)
1294                 (void)fprintf(stderr, "%s\n", usg_hdr);
1295
1296         /* load directory or file */
1297         if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) {
1298                 dir = opendir(fn);
1299                 if (!dir) {
1300                         errs++;
1301                         goto out;
1302                 }
1303                 while ((d = readdir(dir)) != NULL) {
1304                         if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) {
1305                                 file_oomem(ms,
1306                                     strlen(fn) + strlen(d->d_name) + 2);
1307                                 errs++;
1308                                 closedir(dir);
1309                                 goto out;
1310                         }
1311                         if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) {
1312                                 free(mfn);
1313                                 continue;
1314                         }
1315                         if (files >= maxfiles) {
1316                                 size_t mlen;
1317                                 maxfiles = (maxfiles + 1) * 2;
1318                                 mlen = maxfiles * sizeof(*filearr);
1319                                 if ((filearr = CAST(char **,
1320                                     realloc(filearr, mlen))) == NULL) {
1321                                         file_oomem(ms, mlen);
1322                                         free(mfn);
1323                                         closedir(dir);
1324                                         errs++;
1325                                         goto out;
1326                                 }
1327                         }
1328                         filearr[files++] = mfn;
1329                 }
1330                 closedir(dir);
1331                 qsort(filearr, files, sizeof(*filearr), cmpstrp);
1332                 for (i = 0; i < files; i++) {
1333                         load_1(ms, action, filearr[i], &errs, mset);
1334                         free(filearr[i]);
1335                 }
1336                 free(filearr);
1337         } else
1338                 load_1(ms, action, fn, &errs, mset);
1339         if (errs)
1340                 goto out;
1341
1342         for (j = 0; j < MAGIC_SETS; j++) {
1343                 /* Set types of tests */
1344                 for (i = 0; i < mset[j].count; ) {
1345                         if (mset[j].me[i].mp->cont_level != 0) {
1346                                 i++;
1347                                 continue;
1348                         }
1349                         i = set_text_binary(ms, mset[j].me, mset[j].count, i);
1350                 }
1351                 qsort(mset[j].me, mset[j].count, sizeof(*mset[j].me),
1352                     apprentice_sort);
1353
1354                 /*
1355                  * Make sure that any level 0 "default" line is last
1356                  * (if one exists).
1357                  */
1358                 set_last_default(ms, mset[j].me, mset[j].count);
1359
1360                 /* coalesce per file arrays into a single one */
1361                 if (coalesce_entries(ms, mset[j].me, mset[j].count,
1362                     &map->magic[j], &map->nmagic[j]) == -1) {
1363                         errs++;
1364                         goto out;
1365                 }
1366         }
1367
1368 out:
1369         for (j = 0; j < MAGIC_SETS; j++)
1370                 magic_entry_free(mset[j].me, mset[j].count);
1371
1372         if (errs) {
1373                 apprentice_unmap(map);
1374                 return NULL;
1375         }
1376         return map;
1377 }
1378
1379 /*
1380  * extend the sign bit if the comparison is to be signed
1381  */
1382 protected uint64_t
1383 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
1384 {
1385         if (!(m->flag & UNSIGNED)) {
1386                 switch(m->type) {
1387                 /*
1388                  * Do not remove the casts below.  They are
1389                  * vital.  When later compared with the data,
1390                  * the sign extension must have happened.
1391                  */
1392                 case FILE_BYTE:
1393                         v = (signed char) v;
1394                         break;
1395                 case FILE_SHORT:
1396                 case FILE_BESHORT:
1397                 case FILE_LESHORT:
1398                         v = (short) v;
1399                         break;
1400                 case FILE_DATE:
1401                 case FILE_BEDATE:
1402                 case FILE_LEDATE:
1403                 case FILE_MEDATE:
1404                 case FILE_LDATE:
1405                 case FILE_BELDATE:
1406                 case FILE_LELDATE:
1407                 case FILE_MELDATE:
1408                 case FILE_LONG:
1409                 case FILE_BELONG:
1410                 case FILE_LELONG:
1411                 case FILE_MELONG:
1412                 case FILE_FLOAT:
1413                 case FILE_BEFLOAT:
1414                 case FILE_LEFLOAT:
1415                         v = (int32_t) v;
1416                         break;
1417                 case FILE_QUAD:
1418                 case FILE_BEQUAD:
1419                 case FILE_LEQUAD:
1420                 case FILE_QDATE:
1421                 case FILE_QLDATE:
1422                 case FILE_QWDATE:
1423                 case FILE_BEQDATE:
1424                 case FILE_BEQLDATE:
1425                 case FILE_BEQWDATE:
1426                 case FILE_LEQDATE:
1427                 case FILE_LEQLDATE:
1428                 case FILE_LEQWDATE:
1429                 case FILE_DOUBLE:
1430                 case FILE_BEDOUBLE:
1431                 case FILE_LEDOUBLE:
1432                         v = (int64_t) v;
1433                         break;
1434                 case FILE_STRING:
1435                 case FILE_PSTRING:
1436                 case FILE_BESTRING16:
1437                 case FILE_LESTRING16:
1438                 case FILE_REGEX:
1439                 case FILE_SEARCH:
1440                 case FILE_DEFAULT:
1441                 case FILE_INDIRECT:
1442                 case FILE_NAME:
1443                 case FILE_USE:
1444                 case FILE_CLEAR:
1445                         break;
1446                 default:
1447                         if (ms->flags & MAGIC_CHECK)
1448                             file_magwarn(ms, "cannot happen: m->type=%d\n",
1449                                     m->type);
1450                         return ~0U;
1451                 }
1452         }
1453         return v;
1454 }
1455
1456 private int
1457 string_modifier_check(struct magic_set *ms, struct magic *m)
1458 {
1459         if ((ms->flags & MAGIC_CHECK) == 0)
1460                 return 0;
1461
1462         if ((m->type != FILE_REGEX || (m->str_flags & REGEX_LINE_COUNT) == 0) &&
1463             (m->type != FILE_PSTRING && (m->str_flags & PSTRING_LEN) != 0)) {
1464                 file_magwarn(ms,
1465                     "'/BHhLl' modifiers are only allowed for pascal strings\n");
1466                 return -1;
1467         }
1468         switch (m->type) {
1469         case FILE_BESTRING16:
1470         case FILE_LESTRING16:
1471                 if (m->str_flags != 0) {
1472                         file_magwarn(ms,
1473                             "no modifiers allowed for 16-bit strings\n");
1474                         return -1;
1475                 }
1476                 break;
1477         case FILE_STRING:
1478         case FILE_PSTRING:
1479                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
1480                         file_magwarn(ms,
1481                             "'/%c' only allowed on regex and search\n",
1482                             CHAR_REGEX_OFFSET_START);
1483                         return -1;
1484                 }
1485                 break;
1486         case FILE_SEARCH:
1487                 if (m->str_range == 0) {
1488                         file_magwarn(ms,
1489                             "missing range; defaulting to %d\n",
1490                             STRING_DEFAULT_RANGE);
1491                         m->str_range = STRING_DEFAULT_RANGE;
1492                         return -1;
1493                 }
1494                 break;
1495         case FILE_REGEX:
1496                 if ((m->str_flags & STRING_COMPACT_WHITESPACE) != 0) {
1497                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1498                             CHAR_COMPACT_WHITESPACE);
1499                         return -1;
1500                 }
1501                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_WHITESPACE) != 0) {
1502                         file_magwarn(ms, "'/%c' not allowed on regex\n",
1503                             CHAR_COMPACT_OPTIONAL_WHITESPACE);
1504                         return -1;
1505                 }
1506                 break;
1507         default:
1508                 file_magwarn(ms, "coding error: m->type=%d\n",
1509                     m->type);
1510                 return -1;
1511         }
1512         return 0;
1513 }
1514
1515 private int
1516 get_op(char c)
1517 {
1518         switch (c) {
1519         case '&':
1520                 return FILE_OPAND;
1521         case '|':
1522                 return FILE_OPOR;
1523         case '^':
1524                 return FILE_OPXOR;
1525         case '+':
1526                 return FILE_OPADD;
1527         case '-':
1528                 return FILE_OPMINUS;
1529         case '*':
1530                 return FILE_OPMULTIPLY;
1531         case '/':
1532                 return FILE_OPDIVIDE;
1533         case '%':
1534                 return FILE_OPMODULO;
1535         default:
1536                 return -1;
1537         }
1538 }
1539
1540 #ifdef ENABLE_CONDITIONALS
1541 private int
1542 get_cond(const char *l, const char **t)
1543 {
1544         static const struct cond_tbl_s {
1545                 char name[8];
1546                 size_t len;
1547                 int cond;
1548         } cond_tbl[] = {
1549                 { "if",         2,      COND_IF },
1550                 { "elif",       4,      COND_ELIF },
1551                 { "else",       4,      COND_ELSE },
1552                 { "",           0,      COND_NONE },
1553         };
1554         const struct cond_tbl_s *p;
1555
1556         for (p = cond_tbl; p->len; p++) {
1557                 if (strncmp(l, p->name, p->len) == 0 &&
1558                     isspace((unsigned char)l[p->len])) {
1559                         if (t)
1560                                 *t = l + p->len;
1561                         break;
1562                 }
1563         }
1564         return p->cond;
1565 }
1566
1567 private int
1568 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
1569 {
1570         int last_cond;
1571         last_cond = ms->c.li[cont_level].last_cond;
1572
1573         switch (cond) {
1574         case COND_IF:
1575                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
1576                         if (ms->flags & MAGIC_CHECK)
1577                                 file_magwarn(ms, "syntax error: `if'");
1578                         return -1;
1579                 }
1580                 last_cond = COND_IF;
1581                 break;
1582
1583         case COND_ELIF:
1584                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1585                         if (ms->flags & MAGIC_CHECK)
1586                                 file_magwarn(ms, "syntax error: `elif'");
1587                         return -1;
1588                 }
1589                 last_cond = COND_ELIF;
1590                 break;
1591
1592         case COND_ELSE:
1593                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
1594                         if (ms->flags & MAGIC_CHECK)
1595                                 file_magwarn(ms, "syntax error: `else'");
1596                         return -1;
1597                 }
1598                 last_cond = COND_NONE;
1599                 break;
1600
1601         case COND_NONE:
1602                 last_cond = COND_NONE;
1603                 break;
1604         }
1605
1606         ms->c.li[cont_level].last_cond = last_cond;
1607         return 0;
1608 }
1609 #endif /* ENABLE_CONDITIONALS */
1610
1611 private int
1612 parse_indirect_modifier(struct magic_set *ms, struct magic *m, const char **lp)
1613 {
1614         const char *l = *lp;
1615
1616         while (!isspace((unsigned char)*++l))
1617                 switch (*l) {
1618                 case CHAR_INDIRECT_RELATIVE:
1619                         m->str_flags |= INDIRECT_RELATIVE;
1620                         break;
1621                 default:
1622                         if (ms->flags & MAGIC_CHECK)
1623                                 file_magwarn(ms, "indirect modifier `%c' "
1624                                         "invalid", *l);
1625                         *lp = l;
1626                         return -1;
1627                 }
1628         *lp = l;
1629         return 0;
1630 }
1631
1632 private void
1633 parse_op_modifier(struct magic_set *ms, struct magic *m, const char **lp,
1634     int op)
1635 {
1636         const char *l = *lp;
1637         char *t;
1638         uint64_t val;
1639
1640         ++l;
1641         m->mask_op |= op;
1642         val = (uint64_t)strtoull(l, &t, 0);
1643         l = t;
1644         m->num_mask = file_signextend(ms, m, val);
1645         eatsize(&l);
1646         *lp = l;
1647 }
1648
1649 private int
1650 parse_string_modifier(struct magic_set *ms, struct magic *m, const char **lp)
1651 {
1652         const char *l = *lp;
1653         char *t;
1654         int have_range = 0;
1655
1656         while (!isspace((unsigned char)*++l)) {
1657                 switch (*l) {
1658                 case '0':  case '1':  case '2':
1659                 case '3':  case '4':  case '5':
1660                 case '6':  case '7':  case '8':
1661                 case '9':
1662                         if (have_range && (ms->flags & MAGIC_CHECK))
1663                                 file_magwarn(ms, "multiple ranges");
1664                         have_range = 1;
1665                         m->str_range = CAST(uint32_t, strtoul(l, &t, 0));
1666                         if (m->str_range == 0)
1667                                 file_magwarn(ms, "zero range");
1668                         l = t - 1;
1669                         break;
1670                 case CHAR_COMPACT_WHITESPACE:
1671                         m->str_flags |= STRING_COMPACT_WHITESPACE;
1672                         break;
1673                 case CHAR_COMPACT_OPTIONAL_WHITESPACE:
1674                         m->str_flags |= STRING_COMPACT_OPTIONAL_WHITESPACE;
1675                         break;
1676                 case CHAR_IGNORE_LOWERCASE:
1677                         m->str_flags |= STRING_IGNORE_LOWERCASE;
1678                         break;
1679                 case CHAR_IGNORE_UPPERCASE:
1680                         m->str_flags |= STRING_IGNORE_UPPERCASE;
1681                         break;
1682                 case CHAR_REGEX_OFFSET_START:
1683                         m->str_flags |= REGEX_OFFSET_START;
1684                         break;
1685                 case CHAR_BINTEST:
1686                         m->str_flags |= STRING_BINTEST;
1687                         break;
1688                 case CHAR_TEXTTEST:
1689                         m->str_flags |= STRING_TEXTTEST;
1690                         break;
1691                 case CHAR_TRIM:
1692                         m->str_flags |= STRING_TRIM;
1693                         break;
1694                 case CHAR_PSTRING_1_LE:
1695 #define SET_LENGTH(a) m->str_flags = (m->str_flags & ~PSTRING_LEN) | (a)
1696                         if (m->type != FILE_PSTRING)
1697                                 goto bad;
1698                         SET_LENGTH(PSTRING_1_LE);
1699                         break;
1700                 case CHAR_PSTRING_2_BE:
1701                         if (m->type != FILE_PSTRING)
1702                                 goto bad;
1703                         SET_LENGTH(PSTRING_2_BE);
1704                         break;
1705                 case CHAR_PSTRING_2_LE:
1706                         if (m->type != FILE_PSTRING)
1707                                 goto bad;
1708                         SET_LENGTH(PSTRING_2_LE);
1709                         break;
1710                 case CHAR_PSTRING_4_BE:
1711                         if (m->type != FILE_PSTRING)
1712                                 goto bad;
1713                         SET_LENGTH(PSTRING_4_BE);
1714                         break;
1715                 case CHAR_PSTRING_4_LE:
1716                         switch (m->type) {
1717                         case FILE_PSTRING:
1718                         case FILE_REGEX:
1719                                 break;
1720                         default:
1721                                 goto bad;
1722                         }
1723                         SET_LENGTH(PSTRING_4_LE);
1724                         break;
1725                 case CHAR_PSTRING_LENGTH_INCLUDES_ITSELF:
1726                         if (m->type != FILE_PSTRING)
1727                                 goto bad;
1728                         m->str_flags |= PSTRING_LENGTH_INCLUDES_ITSELF;
1729                         break;
1730                 default:
1731                 bad:
1732                         if (ms->flags & MAGIC_CHECK)
1733                                 file_magwarn(ms, "string modifier `%c' "
1734                                         "invalid", *l);
1735                         goto out;
1736                 }
1737                 /* allow multiple '/' for readability */
1738                 if (l[1] == '/' && !isspace((unsigned char)l[2]))
1739                         l++;
1740         }
1741         if (string_modifier_check(ms, m) == -1)
1742                 goto out;
1743         *lp = l;
1744         return 0;
1745 out:
1746         *lp = l;
1747         return -1;
1748 }
1749
1750 /*
1751  * parse one line from magic file, put into magic[index++] if valid
1752  */
1753 private int
1754 parse(struct magic_set *ms, struct magic_entry *me, const char *line,
1755     size_t lineno, int action)
1756 {
1757 #ifdef ENABLE_CONDITIONALS
1758         static uint32_t last_cont_level = 0;
1759 #endif
1760         size_t i;
1761         struct magic *m;
1762         const char *l = line;
1763         char *t;
1764         int op;
1765         uint32_t cont_level;
1766         int32_t diff;
1767
1768         cont_level = 0;
1769
1770         /*
1771          * Parse the offset.
1772          */
1773         while (*l == '>') {
1774                 ++l;            /* step over */
1775                 cont_level++; 
1776         }
1777 #ifdef ENABLE_CONDITIONALS
1778         if (cont_level == 0 || cont_level > last_cont_level)
1779                 if (file_check_mem(ms, cont_level) == -1)
1780                         return -1;
1781         last_cont_level = cont_level;
1782 #endif
1783         if (cont_level != 0) {
1784                 if (me->mp == NULL) {
1785                         file_magerror(ms, "No current entry for continuation");
1786                         return -1;
1787                 }
1788                 if (me->cont_count == 0) {
1789                         file_magerror(ms, "Continuations present with 0 count");
1790                         return -1;
1791                 }
1792                 m = &me->mp[me->cont_count - 1];
1793                 diff = (int32_t)cont_level - (int32_t)m->cont_level;
1794                 if (diff > 1)
1795                         file_magwarn(ms, "New continuation level %u is more "
1796                             "than one larger than current level %u", cont_level,
1797                             m->cont_level);
1798                 if (me->cont_count == me->max_count) {
1799                         struct magic *nm;
1800                         size_t cnt = me->max_count + ALLOC_CHUNK;
1801                         if ((nm = CAST(struct magic *, realloc(me->mp,
1802                             sizeof(*nm) * cnt))) == NULL) {
1803                                 file_oomem(ms, sizeof(*nm) * cnt);
1804                                 return -1;
1805                         }
1806                         me->mp = m = nm;
1807                         me->max_count = CAST(uint32_t, cnt);
1808                 }
1809                 m = &me->mp[me->cont_count++];
1810                 (void)memset(m, 0, sizeof(*m));
1811                 m->cont_level = cont_level;
1812         } else {
1813                 static const size_t len = sizeof(*m) * ALLOC_CHUNK;
1814                 if (me->mp != NULL)
1815                         return 1;
1816                 if ((m = CAST(struct magic *, malloc(len))) == NULL) {
1817                         file_oomem(ms, len);
1818                         return -1;
1819                 }
1820                 me->mp = m;
1821                 me->max_count = ALLOC_CHUNK;
1822                 (void)memset(m, 0, sizeof(*m));
1823                 m->factor_op = FILE_FACTOR_OP_NONE;
1824                 m->cont_level = 0;
1825                 me->cont_count = 1;
1826         }
1827         m->lineno = CAST(uint32_t, lineno);
1828
1829         if (*l == '&') {  /* m->cont_level == 0 checked below. */
1830                 ++l;            /* step over */
1831                 m->flag |= OFFADD;
1832         }
1833         if (*l == '(') {
1834                 ++l;            /* step over */
1835                 m->flag |= INDIR;
1836                 if (m->flag & OFFADD)
1837                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
1838
1839                 if (*l == '&') {  /* m->cont_level == 0 checked below */
1840                         ++l;            /* step over */
1841                         m->flag |= OFFADD;
1842                 }
1843         }
1844         /* Indirect offsets are not valid at level 0. */
1845         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) {
1846                 if (ms->flags & MAGIC_CHECK)
1847                         file_magwarn(ms, "relative offset at level 0");
1848                 return -1;
1849         }
1850
1851         /* get offset, then skip over it */
1852         m->offset = (uint32_t)strtoul(l, &t, 0);
1853         if (l == t) {
1854                 if (ms->flags & MAGIC_CHECK)
1855                         file_magwarn(ms, "offset `%s' invalid", l);
1856                 return -1;
1857         }
1858         l = t;
1859
1860         if (m->flag & INDIR) {
1861                 m->in_type = FILE_LONG;
1862                 m->in_offset = 0;
1863                 /*
1864                  * read [.lbs][+-]nnnnn)
1865                  */
1866                 if (*l == '.') {
1867                         l++;
1868                         switch (*l) {
1869                         case 'l':
1870                                 m->in_type = FILE_LELONG;
1871                                 break;
1872                         case 'L':
1873                                 m->in_type = FILE_BELONG;
1874                                 break;
1875                         case 'm':
1876                                 m->in_type = FILE_MELONG;
1877                                 break;
1878                         case 'h':
1879                         case 's':
1880                                 m->in_type = FILE_LESHORT;
1881                                 break;
1882                         case 'H':
1883                         case 'S':
1884                                 m->in_type = FILE_BESHORT;
1885                                 break;
1886                         case 'c':
1887                         case 'b':
1888                         case 'C':
1889                         case 'B':
1890                                 m->in_type = FILE_BYTE;
1891                                 break;
1892                         case 'e':
1893                         case 'f':
1894                         case 'g':
1895                                 m->in_type = FILE_LEDOUBLE;
1896                                 break;
1897                         case 'E':
1898                         case 'F':
1899                         case 'G':
1900                                 m->in_type = FILE_BEDOUBLE;
1901                                 break;
1902                         case 'i':
1903                                 m->in_type = FILE_LEID3;
1904                                 break;
1905                         case 'I':
1906                                 m->in_type = FILE_BEID3;
1907                                 break;
1908                         default:
1909                                 if (ms->flags & MAGIC_CHECK)
1910                                         file_magwarn(ms,
1911                                             "indirect offset type `%c' invalid",
1912                                             *l);
1913                                 return -1;
1914                         }
1915                         l++;
1916                 }
1917
1918                 m->in_op = 0;
1919                 if (*l == '~') {
1920                         m->in_op |= FILE_OPINVERSE;
1921                         l++;
1922                 }
1923                 if ((op = get_op(*l)) != -1) {
1924                         m->in_op |= op;
1925                         l++;
1926                 }
1927                 if (*l == '(') {
1928                         m->in_op |= FILE_OPINDIRECT;
1929                         l++;
1930                 }
1931                 if (isdigit((unsigned char)*l) || *l == '-') {
1932                         m->in_offset = (int32_t)strtol(l, &t, 0);
1933                         if (l == t) {
1934                                 if (ms->flags & MAGIC_CHECK)
1935                                         file_magwarn(ms,
1936                                             "in_offset `%s' invalid", l);
1937                                 return -1;
1938                         }
1939                         l = t;
1940                 }
1941                 if (*l++ != ')' || 
1942                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) {
1943                         if (ms->flags & MAGIC_CHECK)
1944                                 file_magwarn(ms,
1945                                     "missing ')' in indirect offset");
1946                         return -1;
1947                 }
1948         }
1949         EATAB;
1950
1951 #ifdef ENABLE_CONDITIONALS
1952         m->cond = get_cond(l, &l);
1953         if (check_cond(ms, m->cond, cont_level) == -1)
1954                 return -1;
1955
1956         EATAB;
1957 #endif
1958
1959         /*
1960          * Parse the type.
1961          */
1962         if (*l == 'u') {
1963                 /*
1964                  * Try it as a keyword type prefixed by "u"; match what
1965                  * follows the "u".  If that fails, try it as an SUS
1966                  * integer type. 
1967                  */
1968                 m->type = get_type(type_tbl, l + 1, &l);
1969                 if (m->type == FILE_INVALID) {
1970                         /*
1971                          * Not a keyword type; parse it as an SUS type,
1972                          * 'u' possibly followed by a number or C/S/L.
1973                          */
1974                         m->type = get_standard_integer_type(l, &l);
1975                 }
1976                 /* It's unsigned. */
1977                 if (m->type != FILE_INVALID)
1978                         m->flag |= UNSIGNED;
1979         } else {
1980                 /*
1981                  * Try it as a keyword type.  If that fails, try it as
1982                  * an SUS integer type if it begins with "d" or as an
1983                  * SUS string type if it begins with "s".  In any case,
1984                  * it's not unsigned.
1985                  */
1986                 m->type = get_type(type_tbl, l, &l);
1987                 if (m->type == FILE_INVALID) {
1988                         /*
1989                          * Not a keyword type; parse it as an SUS type,
1990                          * either 'd' possibly followed by a number or
1991                          * C/S/L, or just 's'.
1992                          */
1993                         if (*l == 'd')
1994                                 m->type = get_standard_integer_type(l, &l);
1995                         else if (*l == 's' && !isalpha((unsigned char)l[1])) {
1996                                 m->type = FILE_STRING;
1997                                 ++l;
1998                         }
1999                 }
2000         }
2001
2002         if (m->type == FILE_INVALID) {
2003                 /* Not found - try it as a special keyword. */
2004                 m->type = get_type(special_tbl, l, &l);
2005         }
2006                         
2007         if (m->type == FILE_INVALID) {
2008                 if (ms->flags & MAGIC_CHECK)
2009                         file_magwarn(ms, "type `%s' invalid", l);
2010                 return -1;
2011         }
2012
2013         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
2014         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
2015
2016         m->mask_op = 0;
2017         if (*l == '~') {
2018                 if (!IS_STRING(m->type))
2019                         m->mask_op |= FILE_OPINVERSE;
2020                 else if (ms->flags & MAGIC_CHECK)
2021                         file_magwarn(ms, "'~' invalid for string types");
2022                 ++l;
2023         }
2024         m->str_range = 0;
2025         m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0;
2026         if ((op = get_op(*l)) != -1) {
2027                 if (IS_STRING(m->type)) {
2028                         int r;
2029
2030                         if (op != FILE_OPDIVIDE) {
2031                                 if (ms->flags & MAGIC_CHECK)
2032                                         file_magwarn(ms,
2033                                             "invalid string/indirect op: "
2034                                             "`%c'", *t);
2035                                 return -1;
2036                         }
2037
2038                         if (m->type == FILE_INDIRECT)
2039                                 r = parse_indirect_modifier(ms, m, &l);
2040                         else
2041                                 r = parse_string_modifier(ms, m, &l);
2042                         if (r == -1)
2043                                 return -1;
2044                 } else
2045                         parse_op_modifier(ms, m, &l, op);
2046         }
2047
2048         /*
2049          * We used to set mask to all 1's here, instead let's just not do
2050          * anything if mask = 0 (unless you have a better idea)
2051          */
2052         EATAB;
2053   
2054         switch (*l) {
2055         case '>':
2056         case '<':
2057                 m->reln = *l;
2058                 ++l;
2059                 if (*l == '=') {
2060                         if (ms->flags & MAGIC_CHECK) {
2061                                 file_magwarn(ms, "%c= not supported",
2062                                     m->reln);
2063                                 return -1;
2064                         }
2065                    ++l;
2066                 }
2067                 break;
2068         /* Old-style anding: "0 byte &0x80 dynamically linked" */
2069         case '&':
2070         case '^':
2071         case '=':
2072                 m->reln = *l;
2073                 ++l;
2074                 if (*l == '=') {
2075                    /* HP compat: ignore &= etc. */
2076                    ++l;
2077                 }
2078                 break;
2079         case '!':
2080                 m->reln = *l;
2081                 ++l;
2082                 break;
2083         default:
2084                 m->reln = '=';  /* the default relation */
2085                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
2086                     isspace((unsigned char)l[1])) || !l[1])) {
2087                         m->reln = *l;
2088                         ++l;
2089                 }
2090                 break;
2091         }
2092         /*
2093          * Grab the value part, except for an 'x' reln.
2094          */
2095         if (m->reln != 'x' && getvalue(ms, m, &l, action))
2096                 return -1;
2097
2098         /*
2099          * TODO finish this macro and start using it!
2100          * #define offsetcheck {if (offset > HOWMANY-1) 
2101          *      magwarn("offset too big"); }
2102          */
2103
2104         /*
2105          * Now get last part - the description
2106          */
2107         EATAB;
2108         if (l[0] == '\b') {
2109                 ++l;
2110                 m->flag |= NOSPACE;
2111         } else if ((l[0] == '\\') && (l[1] == 'b')) {
2112                 ++l;
2113                 ++l;
2114                 m->flag |= NOSPACE;
2115         }
2116         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
2117                 continue;
2118         if (i == sizeof(m->desc)) {
2119                 m->desc[sizeof(m->desc) - 1] = '\0';
2120                 if (ms->flags & MAGIC_CHECK)
2121                         file_magwarn(ms, "description `%s' truncated", m->desc);
2122         }
2123
2124         /*
2125          * We only do this check while compiling, or if any of the magic
2126          * files were not compiled.
2127          */
2128         if (ms->flags & MAGIC_CHECK) {
2129                 if (check_format(ms, m) == -1)
2130                         return -1;
2131         }
2132 #ifndef COMPILE_ONLY
2133         if (action == FILE_CHECK) {
2134                 file_mdump(m);
2135         }
2136 #endif
2137         m->mimetype[0] = '\0';          /* initialise MIME type to none */
2138         return 0;
2139 }
2140
2141 /*
2142  * parse a STRENGTH annotation line from magic file, put into magic[index - 1]
2143  * if valid
2144  */
2145 private int
2146 parse_strength(struct magic_set *ms, struct magic_entry *me, const char *line)
2147 {
2148         const char *l = line;
2149         char *el;
2150         unsigned long factor;
2151         struct magic *m = &me->mp[0];
2152
2153         if (m->factor_op != FILE_FACTOR_OP_NONE) {
2154                 file_magwarn(ms,
2155                     "Current entry already has a strength type: %c %d",
2156                     m->factor_op, m->factor);
2157                 return -1;
2158         }
2159         if (m->type == FILE_NAME) {
2160                 file_magwarn(ms, "%s: Strength setting is not supported in "
2161                     "\"name\" magic entries", m->value.s);
2162                 return -1;
2163         }
2164         EATAB;
2165         switch (*l) {
2166         case FILE_FACTOR_OP_NONE:
2167         case FILE_FACTOR_OP_PLUS:
2168         case FILE_FACTOR_OP_MINUS:
2169         case FILE_FACTOR_OP_TIMES:
2170         case FILE_FACTOR_OP_DIV:
2171                 m->factor_op = *l++;
2172                 break;
2173         default:
2174                 file_magwarn(ms, "Unknown factor op `%c'", *l);
2175                 return -1;
2176         }
2177         EATAB;
2178         factor = strtoul(l, &el, 0);
2179         if (factor > 255) {
2180                 file_magwarn(ms, "Too large factor `%lu'", factor);
2181                 goto out;
2182         }
2183         if (*el && !isspace((unsigned char)*el)) {
2184                 file_magwarn(ms, "Bad factor `%s'", l);
2185                 goto out;
2186         }
2187         m->factor = (uint8_t)factor;
2188         if (m->factor == 0 && m->factor_op == FILE_FACTOR_OP_DIV) {
2189                 file_magwarn(ms, "Cannot have factor op `%c' and factor %u",
2190                     m->factor_op, m->factor);
2191                 goto out;
2192         }
2193         return 0;
2194 out:
2195         m->factor_op = FILE_FACTOR_OP_NONE;
2196         m->factor = 0;
2197         return -1;
2198 }
2199
2200 private int
2201 goodchar(unsigned char x, const char *extra)
2202 {
2203         return (isascii(x) && isalnum(x)) || strchr(extra, x);
2204 }
2205
2206 private int
2207 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line,
2208     off_t off, size_t len, const char *name, const char *extra, int nt)
2209 {
2210         size_t i;
2211         const char *l = line;
2212         struct magic *m = &me->mp[me->cont_count == 0 ? 0 : me->cont_count - 1];
2213         char *buf = CAST(char *, CAST(void *, m)) + off;
2214
2215         if (buf[0] != '\0') {
2216                 len = nt ? strlen(buf) : len;
2217                 file_magwarn(ms, "Current entry already has a %s type "
2218                     "`%.*s', new type `%s'", name, (int)len, buf, l);
2219                 return -1;
2220         }       
2221
2222         if (*m->desc == '\0') {
2223                 file_magwarn(ms, "Current entry does not yet have a "
2224                     "description for adding a %s type", name);
2225                 return -1;
2226         }
2227
2228         EATAB;
2229         for (i = 0; *l && i < len && goodchar(*l, extra); buf[i++] = *l++)
2230                 continue;
2231
2232         if (i == len && *l) {
2233                 if (nt)
2234                         buf[len - 1] = '\0';
2235                 if (ms->flags & MAGIC_CHECK)
2236                         file_magwarn(ms, "%s type `%s' truncated %"
2237                             SIZE_T_FORMAT "u", name, line, i);
2238         } else {
2239                 if (!isspace((unsigned char)*l) && !goodchar(*l, extra))
2240                         file_magwarn(ms, "%s type `%s' has bad char '%c'",
2241                             name, line, *l);
2242                 if (nt)
2243                         buf[i] = '\0';
2244         }
2245
2246         if (i > 0)
2247                 return 0;
2248
2249         file_magerror(ms, "Bad magic entry '%s'", line);
2250         return -1;
2251 }
2252
2253 /*
2254  * Parse an Apple CREATOR/TYPE annotation from magic file and put it into
2255  * magic[index - 1]
2256  */
2257 private int
2258 parse_apple(struct magic_set *ms, struct magic_entry *me, const char *line)
2259 {
2260         struct magic *m = &me->mp[0];
2261
2262         return parse_extra(ms, me, line,
2263             CAST(off_t, offsetof(struct magic, apple)),
2264             sizeof(m->apple), "APPLE", "!+-./", 0);
2265 }
2266
2267 /*
2268  * Parse a comma-separated list of extensions
2269  */
2270 private int
2271 parse_ext(struct magic_set *ms, struct magic_entry *me, const char *line)
2272 {
2273         struct magic *m = &me->mp[0];
2274
2275         return parse_extra(ms, me, line,
2276             CAST(off_t, offsetof(struct magic, ext)),
2277             sizeof(m->ext), "EXTENSION", ",!+-/", 0);
2278 }
2279
2280 /*
2281  * parse a MIME annotation line from magic file, put into magic[index - 1]
2282  * if valid
2283  */
2284 private int
2285 parse_mime(struct magic_set *ms, struct magic_entry *me, const char *line)
2286 {
2287         struct magic *m = &me->mp[0];
2288
2289         return parse_extra(ms, me, line,
2290             CAST(off_t, offsetof(struct magic, mimetype)),
2291             sizeof(m->mimetype), "MIME", "+-/.", 1);
2292 }
2293
2294 private int
2295 check_format_type(const char *ptr, int type)
2296 {
2297         int quad = 0, h;
2298         if (*ptr == '\0') {
2299                 /* Missing format string; bad */
2300                 return -1;
2301         }
2302
2303         switch (file_formats[type]) {
2304         case FILE_FMT_QUAD:
2305                 quad = 1;
2306                 /*FALLTHROUGH*/
2307         case FILE_FMT_NUM:
2308                 if (quad == 0) {
2309                         switch (type) {
2310                         case FILE_BYTE:
2311                                 h = 2;
2312                                 break;
2313                         case FILE_SHORT:
2314                         case FILE_BESHORT:
2315                         case FILE_LESHORT:
2316                                 h = 1;
2317                                 break;
2318                         case FILE_LONG:
2319                         case FILE_BELONG:
2320                         case FILE_LELONG:
2321                         case FILE_MELONG:
2322                         case FILE_LEID3:
2323                         case FILE_BEID3:
2324                         case FILE_INDIRECT:
2325                                 h = 0;
2326                                 break;
2327                         default:
2328                                 abort();
2329                         }
2330                 } else
2331                         h = 0;
2332                 if (*ptr == '-')
2333                         ptr++;
2334                 if (*ptr == '.')
2335                         ptr++;
2336                 while (isdigit((unsigned char)*ptr)) ptr++;
2337                 if (*ptr == '.')
2338                         ptr++;
2339                 while (isdigit((unsigned char)*ptr)) ptr++;
2340                 if (quad) {
2341                         if (*ptr++ != 'l')
2342                                 return -1;
2343                         if (*ptr++ != 'l')
2344                                 return -1;
2345                 }
2346         
2347                 switch (*ptr++) {
2348 #ifdef STRICT_FORMAT    /* "long" formats are int formats for us */
2349                 /* so don't accept the 'l' modifier */
2350                 case 'l':
2351                         switch (*ptr++) {
2352                         case 'i':
2353                         case 'd':
2354                         case 'u':
2355                         case 'o':
2356                         case 'x':
2357                         case 'X':
2358                                 return h != 0 ? -1 : 0;
2359                         default:
2360                                 return -1;
2361                         }
2362                 
2363                 /*
2364                  * Don't accept h and hh modifiers. They make writing
2365                  * magic entries more complicated, for very little benefit
2366                  */
2367                 case 'h':
2368                         if (h-- <= 0)
2369                                 return -1;
2370                         switch (*ptr++) {
2371                         case 'h':
2372                                 if (h-- <= 0)
2373                                         return -1;
2374                                 switch (*ptr++) {
2375                                 case 'i':
2376                                 case 'd':
2377                                 case 'u':
2378                                 case 'o':
2379                                 case 'x':
2380                                 case 'X':
2381                                         return 0;
2382                                 default:
2383                                         return -1;
2384                                 }
2385                         case 'i':
2386                         case 'd':
2387                         case 'u':
2388                         case 'o':
2389                         case 'x':
2390                         case 'X':
2391                                 return h != 0 ? -1 : 0;
2392                         default:
2393                                 return -1;
2394                         }
2395 #endif
2396                 case 'c':
2397                         return h != 2 ? -1 : 0;
2398                 case 'i':
2399                 case 'd':
2400                 case 'u':
2401                 case 'o':
2402                 case 'x':
2403                 case 'X':
2404 #ifdef STRICT_FORMAT
2405                         return h != 0 ? -1 : 0;
2406 #else
2407                         return 0;
2408 #endif
2409                 default:
2410                         return -1;
2411                 }
2412                 
2413         case FILE_FMT_FLOAT:
2414         case FILE_FMT_DOUBLE:
2415                 if (*ptr == '-')
2416                         ptr++;
2417                 if (*ptr == '.')
2418                         ptr++;
2419                 while (isdigit((unsigned char)*ptr)) ptr++;
2420                 if (*ptr == '.')
2421                         ptr++;
2422                 while (isdigit((unsigned char)*ptr)) ptr++;
2423         
2424                 switch (*ptr++) {
2425                 case 'e':
2426                 case 'E':
2427                 case 'f':
2428                 case 'F':
2429                 case 'g':
2430                 case 'G':
2431                         return 0;
2432                         
2433                 default:
2434                         return -1;
2435                 }
2436                 
2437
2438         case FILE_FMT_STR:
2439                 if (*ptr == '-')
2440                         ptr++;
2441                 while (isdigit((unsigned char )*ptr))
2442                         ptr++;
2443                 if (*ptr == '.') {
2444                         ptr++;
2445                         while (isdigit((unsigned char )*ptr))
2446                                 ptr++;
2447                 }
2448                 
2449                 switch (*ptr++) {
2450                 case 's':
2451                         return 0;
2452                 default:
2453                         return -1;
2454                 }
2455                 
2456         default:
2457                 /* internal error */
2458                 abort();
2459         }
2460         /*NOTREACHED*/
2461         return -1;
2462 }
2463         
2464 /*
2465  * Check that the optional printf format in description matches
2466  * the type of the magic.
2467  */
2468 private int
2469 check_format(struct magic_set *ms, struct magic *m)
2470 {
2471         char *ptr;
2472
2473         for (ptr = m->desc; *ptr; ptr++)
2474                 if (*ptr == '%')
2475                         break;
2476         if (*ptr == '\0') {
2477                 /* No format string; ok */
2478                 return 1;
2479         }
2480
2481         assert(file_nformats == file_nnames);
2482
2483         if (m->type >= file_nformats) {
2484                 file_magwarn(ms, "Internal error inconsistency between "
2485                     "m->type and format strings");              
2486                 return -1;
2487         }
2488         if (file_formats[m->type] == FILE_FMT_NONE) {
2489                 file_magwarn(ms, "No format string for `%s' with description "
2490                     "`%s'", m->desc, file_names[m->type]);
2491                 return -1;
2492         }
2493
2494         ptr++;
2495         if (check_format_type(ptr, m->type) == -1) {
2496                 /*
2497                  * TODO: this error message is unhelpful if the format
2498                  * string is not one character long
2499                  */
2500                 file_magwarn(ms, "Printf format `%c' is not valid for type "
2501                     "`%s' in description `%s'", *ptr ? *ptr : '?',
2502                     file_names[m->type], m->desc);
2503                 return -1;
2504         }
2505         
2506         for (; *ptr; ptr++) {
2507                 if (*ptr == '%') {
2508                         file_magwarn(ms,
2509                             "Too many format strings (should have at most one) "
2510                             "for `%s' with description `%s'",
2511                             file_names[m->type], m->desc);
2512                         return -1;
2513                 }
2514         }
2515         return 0;
2516 }
2517
2518 /* 
2519  * Read a numeric value from a pointer, into the value union of a magic 
2520  * pointer, according to the magic type.  Update the string pointer to point 
2521  * just after the number read.  Return 0 for success, non-zero for failure.
2522  */
2523 private int
2524 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
2525 {
2526         switch (m->type) {
2527         case FILE_BESTRING16:
2528         case FILE_LESTRING16:
2529         case FILE_STRING:
2530         case FILE_PSTRING:
2531         case FILE_REGEX:
2532         case FILE_SEARCH:
2533         case FILE_NAME:
2534         case FILE_USE:
2535                 *p = getstr(ms, m, *p, action == FILE_COMPILE);
2536                 if (*p == NULL) {
2537                         if (ms->flags & MAGIC_CHECK)
2538                                 file_magwarn(ms, "cannot get string from `%s'",
2539                                     m->value.s);
2540                         return -1;
2541                 }
2542                 if (m->type == FILE_REGEX) {
2543                         file_regex_t rx;
2544                         int rc = file_regcomp(&rx, m->value.s, REG_EXTENDED);
2545                         if (rc) {
2546                                 if (ms->flags & MAGIC_CHECK)
2547                                         file_regerror(&rx, rc, ms);
2548                         }
2549                         file_regfree(&rx);
2550                         return rc ? -1 : 0;
2551                 }
2552                 return 0;
2553         case FILE_FLOAT:
2554         case FILE_BEFLOAT:
2555         case FILE_LEFLOAT:
2556                 if (m->reln != 'x') {
2557                         char *ep;
2558 #ifdef HAVE_STRTOF
2559                         m->value.f = strtof(*p, &ep);
2560 #else
2561                         m->value.f = (float)strtod(*p, &ep);
2562 #endif
2563                         *p = ep;
2564                 }
2565                 return 0;
2566         case FILE_DOUBLE:
2567         case FILE_BEDOUBLE:
2568         case FILE_LEDOUBLE:
2569                 if (m->reln != 'x') {
2570                         char *ep;
2571                         m->value.d = strtod(*p, &ep);
2572                         *p = ep;
2573                 }
2574                 return 0;
2575         default:
2576                 if (m->reln != 'x') {
2577                         char *ep;
2578                         m->value.q = file_signextend(ms, m,
2579                             (uint64_t)strtoull(*p, &ep, 0));
2580                         *p = ep;
2581                         eatsize(p);
2582                 }
2583                 return 0;
2584         }
2585 }
2586
2587 /*
2588  * Convert a string containing C character escapes.  Stop at an unescaped
2589  * space or tab.
2590  * Copy the converted version to "m->value.s", and the length in m->vallen.
2591  * Return updated scan pointer as function result. Warn if set.
2592  */
2593 private const char *
2594 getstr(struct magic_set *ms, struct magic *m, const char *s, int warn)
2595 {
2596         const char *origs = s;
2597         char    *p = m->value.s;
2598         size_t  plen = sizeof(m->value.s);
2599         char    *origp = p;
2600         char    *pmax = p + plen - 1;
2601         int     c;
2602         int     val;
2603
2604         while ((c = *s++) != '\0') {
2605                 if (isspace((unsigned char) c))
2606                         break;
2607                 if (p >= pmax) {
2608                         file_error(ms, 0, "string too long: `%s'", origs);
2609                         return NULL;
2610                 }
2611                 if (c == '\\') {
2612                         switch(c = *s++) {
2613
2614                         case '\0':
2615                                 if (warn)
2616                                         file_magwarn(ms, "incomplete escape");
2617                                 goto out;
2618
2619                         case '\t':
2620                                 if (warn) {
2621                                         file_magwarn(ms,
2622                                             "escaped tab found, use \\t instead");
2623                                         warn = 0;       /* already did */
2624                                 }
2625                                 /*FALLTHROUGH*/
2626                         default:
2627                                 if (warn) {
2628                                         if (isprint((unsigned char)c)) {
2629                                                 /* Allow escaping of 
2630                                                  * ``relations'' */
2631                                                 if (strchr("<>&^=!", c) == NULL
2632                                                     && (m->type != FILE_REGEX ||
2633                                                     strchr("[]().*?^$|{}", c)
2634                                                     == NULL)) {
2635                                                         file_magwarn(ms, "no "
2636                                                             "need to escape "
2637                                                             "`%c'", c);
2638                                                 }
2639                                         } else {
2640                                                 file_magwarn(ms,
2641                                                     "unknown escape sequence: "
2642                                                     "\\%03o", c);
2643                                         }
2644                                 }
2645                                 /*FALLTHROUGH*/
2646                         /* space, perhaps force people to use \040? */
2647                         case ' ':
2648 #if 0
2649                         /*
2650                          * Other things people escape, but shouldn't need to,
2651                          * so we disallow them
2652                          */
2653                         case '\'':
2654                         case '"':
2655                         case '?':
2656 #endif
2657                         /* Relations */
2658                         case '>':
2659                         case '<':
2660                         case '&':
2661                         case '^':
2662                         case '=':
2663                         case '!':
2664                         /* and baskslash itself */
2665                         case '\\':
2666                                 *p++ = (char) c;
2667                                 break;
2668
2669                         case 'a':
2670                                 *p++ = '\a';
2671                                 break;
2672
2673                         case 'b':
2674                                 *p++ = '\b';
2675                                 break;
2676
2677                         case 'f':
2678                                 *p++ = '\f';
2679                                 break;
2680
2681                         case 'n':
2682                                 *p++ = '\n';
2683                                 break;
2684
2685                         case 'r':
2686                                 *p++ = '\r';
2687                                 break;
2688
2689                         case 't':
2690                                 *p++ = '\t';
2691                                 break;
2692
2693                         case 'v':
2694                                 *p++ = '\v';
2695                                 break;
2696
2697                         /* \ and up to 3 octal digits */
2698                         case '0':
2699                         case '1':
2700                         case '2':
2701                         case '3':
2702                         case '4':
2703                         case '5':
2704                         case '6':
2705                         case '7':
2706                                 val = c - '0';
2707                                 c = *s++;  /* try for 2 */
2708                                 if (c >= '0' && c <= '7') {
2709                                         val = (val << 3) | (c - '0');
2710                                         c = *s++;  /* try for 3 */
2711                                         if (c >= '0' && c <= '7')
2712                                                 val = (val << 3) | (c-'0');
2713                                         else
2714                                                 --s;
2715                                 }
2716                                 else
2717                                         --s;
2718                                 *p++ = (char)val;
2719                                 break;
2720
2721                         /* \x and up to 2 hex digits */
2722                         case 'x':
2723                                 val = 'x';      /* Default if no digits */
2724                                 c = hextoint(*s++);     /* Get next char */
2725                                 if (c >= 0) {
2726                                         val = c;
2727                                         c = hextoint(*s++);
2728                                         if (c >= 0)
2729                                                 val = (val << 4) + c;
2730                                         else
2731                                                 --s;
2732                                 } else
2733                                         --s;
2734                                 *p++ = (char)val;
2735                                 break;
2736                         }
2737                 } else
2738                         *p++ = (char)c;
2739         }
2740 out:
2741         *p = '\0';
2742         m->vallen = CAST(unsigned char, (p - origp));
2743         if (m->type == FILE_PSTRING)
2744                 m->vallen += (unsigned char)file_pstring_length_size(m);
2745         return s;
2746 }
2747
2748
2749 /* Single hex char to int; -1 if not a hex char. */
2750 private int
2751 hextoint(int c)
2752 {
2753         if (!isascii((unsigned char) c))
2754                 return -1;
2755         if (isdigit((unsigned char) c))
2756                 return c - '0';
2757         if ((c >= 'a') && (c <= 'f'))
2758                 return c + 10 - 'a';
2759         if (( c>= 'A') && (c <= 'F'))
2760                 return c + 10 - 'A';
2761         return -1;
2762 }
2763
2764
2765 /*
2766  * Print a string containing C character escapes.
2767  */
2768 protected void
2769 file_showstr(FILE *fp, const char *s, size_t len)
2770 {
2771         char    c;
2772
2773         for (;;) {
2774                 if (len == ~0U) {
2775                         c = *s++;
2776                         if (c == '\0')
2777                                 break;
2778                 }
2779                 else  {
2780                         if (len-- == 0)
2781                                 break;
2782                         c = *s++;
2783                 }
2784                 if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
2785                         (void) fputc(c, fp);
2786                 else {
2787                         (void) fputc('\\', fp);
2788                         switch (c) {
2789                         case '\a':
2790                                 (void) fputc('a', fp);
2791                                 break;
2792
2793                         case '\b':
2794                                 (void) fputc('b', fp);
2795                                 break;
2796
2797                         case '\f':
2798                                 (void) fputc('f', fp);
2799                                 break;
2800
2801                         case '\n':
2802                                 (void) fputc('n', fp);
2803                                 break;
2804
2805                         case '\r':
2806                                 (void) fputc('r', fp);
2807                                 break;
2808
2809                         case '\t':
2810                                 (void) fputc('t', fp);
2811                                 break;
2812
2813                         case '\v':
2814                                 (void) fputc('v', fp);
2815                                 break;
2816
2817                         default:
2818                                 (void) fprintf(fp, "%.3o", c & 0377);
2819                                 break;
2820                         }
2821                 }
2822         }
2823 }
2824
2825 /*
2826  * eatsize(): Eat the size spec from a number [eg. 10UL]
2827  */
2828 private void
2829 eatsize(const char **p)
2830 {
2831         const char *l = *p;
2832
2833         if (LOWCASE(*l) == 'u') 
2834                 l++;
2835
2836         switch (LOWCASE(*l)) {
2837         case 'l':    /* long */
2838         case 's':    /* short */
2839         case 'h':    /* short */
2840         case 'b':    /* char/byte */
2841         case 'c':    /* char/byte */
2842                 l++;
2843                 /*FALLTHROUGH*/
2844         default:
2845                 break;
2846         }
2847
2848         *p = l;
2849 }
2850
2851 /*
2852  * handle a buffer containing a compiled file.
2853  */
2854 private struct magic_map *
2855 apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len)
2856 {
2857         struct magic_map *map;
2858
2859         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
2860                 file_oomem(ms, sizeof(*map));
2861                 return NULL;
2862         }
2863         map->len = len;
2864         map->p = buf;
2865         map->type = MAP_TYPE_USER;
2866         if (check_buffer(ms, map, "buffer") != 0) {
2867                 apprentice_unmap(map);
2868                 return NULL;
2869         }
2870         return map;
2871 }
2872
2873 /*
2874  * handle a compiled file.
2875  */
2876
2877 private struct magic_map *
2878 apprentice_map(struct magic_set *ms, const char *fn)
2879 {
2880         int fd;
2881         struct stat st;
2882         char *dbname = NULL;
2883         struct magic_map *map;
2884
2885         fd = -1;
2886         if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) {
2887                 file_oomem(ms, sizeof(*map));
2888                 goto error;
2889         }
2890
2891         dbname = mkdbname(ms, fn, 0);
2892         if (dbname == NULL)
2893                 goto error;
2894
2895         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
2896                 goto error;
2897
2898         if (fstat(fd, &st) == -1) {
2899                 file_error(ms, errno, "cannot stat `%s'", dbname);
2900                 goto error;
2901         }
2902         if (st.st_size < 8 || st.st_size > MAXMAGIC_SIZE) {
2903                 file_error(ms, 0, "file `%s' is too %s", dbname,
2904                     st.st_size < 8 ? "small" : "large");
2905                 goto error;
2906         }
2907
2908         map->len = (size_t)st.st_size;
2909 #ifdef QUICK
2910         if ((map->p = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
2911             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
2912                 file_error(ms, errno, "cannot map `%s'", dbname);
2913                 goto error;
2914         }
2915         map->type = MAP_TYPE_MMAP;
2916 #else
2917         if ((map->p = CAST(void *, malloc(map->len))) == NULL) {
2918                 file_oomem(ms, map->len);
2919                 goto error;
2920         }
2921         if (read(fd, map->p, map->len) != (ssize_t)map->len) {
2922                 file_badread(ms);
2923                 goto error;
2924         }
2925         map->type = MAP_TYPE_MALLOC;
2926 #define RET     1
2927 #endif
2928         (void)close(fd);
2929         fd = -1;
2930
2931         if (check_buffer(ms, map, dbname) != 0)
2932                 goto error;
2933
2934         free(dbname);
2935         return map;
2936
2937 error:
2938         if (fd != -1)
2939                 (void)close(fd);
2940         apprentice_unmap(map);
2941         free(dbname);
2942         return NULL;
2943 }
2944
2945 private int
2946 check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname)
2947 {
2948         uint32_t *ptr;
2949         uint32_t entries, nentries;
2950         uint32_t version;
2951         int i, needsbyteswap;
2952
2953         ptr = CAST(uint32_t *, map->p);
2954         if (*ptr != MAGICNO) {
2955                 if (swap4(*ptr) != MAGICNO) {
2956                         file_error(ms, 0, "bad magic in `%s'", dbname);
2957                         return -1;
2958                 }
2959                 needsbyteswap = 1;
2960         } else
2961                 needsbyteswap = 0;
2962         if (needsbyteswap)
2963                 version = swap4(ptr[1]);
2964         else
2965                 version = ptr[1];
2966         if (version != VERSIONNO) {
2967                 file_error(ms, 0, "File %s supports only version %d magic "
2968                     "files. `%s' is version %d", VERSION,
2969                     VERSIONNO, dbname, version);
2970                 return -1;
2971         }
2972         entries = (uint32_t)(map->len / sizeof(struct magic));
2973         if ((entries * sizeof(struct magic)) != map->len) {
2974                 file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not "
2975                     "a multiple of %" SIZE_T_FORMAT "u",
2976                     dbname, map->len, sizeof(struct magic));
2977                 return -1;
2978         }
2979         map->magic[0] = CAST(struct magic *, map->p) + 1;
2980         nentries = 0;
2981         for (i = 0; i < MAGIC_SETS; i++) {
2982                 if (needsbyteswap)
2983                         map->nmagic[i] = swap4(ptr[i + 2]);
2984                 else
2985                         map->nmagic[i] = ptr[i + 2];
2986                 if (i != MAGIC_SETS - 1)
2987                         map->magic[i + 1] = map->magic[i] + map->nmagic[i];
2988                 nentries += map->nmagic[i];
2989         }
2990         if (entries != nentries + 1) {
2991                 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u",
2992                     dbname, entries, nentries + 1);
2993                 return -1;
2994         }
2995         if (needsbyteswap)
2996                 for (i = 0; i < MAGIC_SETS; i++)
2997                         byteswap(map->magic[i], map->nmagic[i]);
2998         return 0;
2999 }
3000
3001 /*
3002  * handle an mmaped file.
3003  */
3004 private int
3005 apprentice_compile(struct magic_set *ms, struct magic_map *map, const char *fn)
3006 {
3007         static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS;
3008         static const size_t m = sizeof(**map->magic);
3009         int fd = -1;
3010         size_t len;
3011         char *dbname;
3012         int rv = -1;
3013         uint32_t i;
3014         union {
3015                 struct magic m;
3016                 uint32_t h[2 + MAGIC_SETS];
3017         } hdr;
3018
3019         dbname = mkdbname(ms, fn, 1);
3020
3021         if (dbname == NULL) 
3022                 goto out;
3023
3024         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 
3025         {
3026                 file_error(ms, errno, "cannot open `%s'", dbname);
3027                 goto out;
3028         }
3029         memset(&hdr, 0, sizeof(hdr));
3030         hdr.h[0] = MAGICNO;
3031         hdr.h[1] = VERSIONNO;
3032         memcpy(hdr.h + 2, map->nmagic, nm);
3033
3034         if (write(fd, &hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) {
3035                 file_error(ms, errno, "error writing `%s'", dbname);
3036                 goto out;
3037         }
3038
3039         for (i = 0; i < MAGIC_SETS; i++) {
3040                 len = m * map->nmagic[i];
3041                 if (write(fd, map->magic[i], len) != (ssize_t)len) {
3042                         file_error(ms, errno, "error writing `%s'", dbname);
3043                         goto out;
3044                 }
3045         }
3046
3047         if (fd != -1)
3048                 (void)close(fd);
3049         rv = 0;
3050 out:
3051         free(dbname);
3052         return rv;
3053 }
3054
3055 private const char ext[] = ".mgc";
3056 /*
3057  * make a dbname
3058  */
3059 private char *
3060 mkdbname(struct magic_set *ms, const char *fn, int strip)
3061 {
3062         const char *p, *q;
3063         char *buf;
3064
3065         if (strip) {
3066                 if ((p = strrchr(fn, '/')) != NULL)
3067                         fn = ++p;
3068         }
3069
3070         for (q = fn; *q; q++)
3071                 continue;
3072         /* Look for .mgc */
3073         for (p = ext + sizeof(ext) - 1; p >= ext && q >= fn; p--, q--)
3074                 if (*p != *q)
3075                         break;
3076
3077         /* Did not find .mgc, restore q */
3078         if (p >= ext)
3079                 while (*q)
3080                         q++;
3081
3082         q++;
3083         /* Compatibility with old code that looked in .mime */
3084         if (ms->flags & MAGIC_MIME) {
3085                 if (asprintf(&buf, "%.*s.mime%s", (int)(q - fn), fn, ext) < 0)
3086                         return NULL;
3087                 if (access(buf, R_OK) != -1) {
3088                         ms->flags &= MAGIC_MIME_TYPE;
3089                         return buf;
3090                 }
3091                 free(buf);
3092         }
3093         if (asprintf(&buf, "%.*s%s", (int)(q - fn), fn, ext) < 0)
3094                 return NULL;
3095
3096         /* Compatibility with old code that looked in .mime */
3097         if (strstr(p, ".mime") != NULL)
3098                 ms->flags &= MAGIC_MIME_TYPE;
3099         return buf;
3100 }
3101
3102 /*
3103  * Byteswap an mmap'ed file if needed
3104  */
3105 private void
3106 byteswap(struct magic *magic, uint32_t nmagic)
3107 {
3108         uint32_t i;
3109         for (i = 0; i < nmagic; i++)
3110                 bs1(&magic[i]);
3111 }
3112
3113 /*
3114  * swap a short
3115  */
3116 private uint16_t
3117 swap2(uint16_t sv)
3118 {
3119         uint16_t rv;
3120         uint8_t *s = (uint8_t *)(void *)&sv; 
3121         uint8_t *d = (uint8_t *)(void *)&rv; 
3122         d[0] = s[1];
3123         d[1] = s[0];
3124         return rv;
3125 }
3126
3127 /*
3128  * swap an int
3129  */
3130 private uint32_t
3131 swap4(uint32_t sv)
3132 {
3133         uint32_t rv;
3134         uint8_t *s = (uint8_t *)(void *)&sv; 
3135         uint8_t *d = (uint8_t *)(void *)&rv; 
3136         d[0] = s[3];
3137         d[1] = s[2];
3138         d[2] = s[1];
3139         d[3] = s[0];
3140         return rv;
3141 }
3142
3143 /*
3144  * swap a quad
3145  */
3146 private uint64_t
3147 swap8(uint64_t sv)
3148 {
3149         uint64_t rv;
3150         uint8_t *s = (uint8_t *)(void *)&sv; 
3151         uint8_t *d = (uint8_t *)(void *)&rv; 
3152 #if 0
3153         d[0] = s[3];
3154         d[1] = s[2];
3155         d[2] = s[1];
3156         d[3] = s[0];
3157         d[4] = s[7];
3158         d[5] = s[6];
3159         d[6] = s[5];
3160         d[7] = s[4];
3161 #else
3162         d[0] = s[7];
3163         d[1] = s[6];
3164         d[2] = s[5];
3165         d[3] = s[4];
3166         d[4] = s[3];
3167         d[5] = s[2];
3168         d[6] = s[1];
3169         d[7] = s[0];
3170 #endif
3171         return rv;
3172 }
3173
3174 /*
3175  * byteswap a single magic entry
3176  */
3177 private void
3178 bs1(struct magic *m)
3179 {
3180         m->cont_level = swap2(m->cont_level);
3181         m->offset = swap4((uint32_t)m->offset);
3182         m->in_offset = swap4((uint32_t)m->in_offset);
3183         m->lineno = swap4((uint32_t)m->lineno);
3184         if (IS_STRING(m->type)) {
3185                 m->str_range = swap4(m->str_range);
3186                 m->str_flags = swap4(m->str_flags);
3187         }
3188         else {
3189                 m->value.q = swap8(m->value.q);
3190                 m->num_mask = swap8(m->num_mask);
3191         }
3192 }
3193
3194 protected size_t 
3195 file_pstring_length_size(const struct magic *m)
3196 {
3197         switch (m->str_flags & PSTRING_LEN) {
3198         case PSTRING_1_LE:
3199                 return 1;
3200         case PSTRING_2_LE:
3201         case PSTRING_2_BE:
3202                 return 2;
3203         case PSTRING_4_LE:
3204         case PSTRING_4_BE:
3205                 return 4;
3206         default:
3207                 abort();        /* Impossible */
3208                 return 1;
3209         }
3210 }
3211 protected size_t
3212 file_pstring_get_length(const struct magic *m, const char *s)
3213 {
3214         size_t len = 0;
3215
3216         switch (m->str_flags & PSTRING_LEN) {
3217         case PSTRING_1_LE:
3218                 len = *s;
3219                 break;
3220         case PSTRING_2_LE:
3221                 len = (s[1] << 8) | s[0];
3222                 break;
3223         case PSTRING_2_BE:
3224                 len = (s[0] << 8) | s[1];
3225                 break;
3226         case PSTRING_4_LE:
3227                 len = (s[3] << 24) | (s[2] << 16) | (s[1] << 8) | s[0];
3228                 break;
3229         case PSTRING_4_BE:
3230                 len = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
3231                 break;
3232         default:
3233                 abort();        /* Impossible */
3234         }
3235
3236         if (m->str_flags & PSTRING_LENGTH_INCLUDES_ITSELF)
3237                 len -= file_pstring_length_size(m);
3238
3239         return len;
3240 }
3241
3242 protected int
3243 file_magicfind(struct magic_set *ms, const char *name, struct mlist *v)
3244 {
3245         uint32_t i, j;
3246         struct mlist *mlist, *ml;
3247
3248         mlist = ms->mlist[1];
3249
3250         for (ml = mlist->next; ml != mlist; ml = ml->next) {
3251                 struct magic *ma = ml->magic;
3252                 uint32_t nma = ml->nmagic;
3253                 for (i = 0; i < nma; i++) {
3254                         if (ma[i].type != FILE_NAME)
3255                                 continue;
3256                         if (strcmp(ma[i].value.s, name) == 0) {
3257                                 v->magic = &ma[i];
3258                                 for (j = i + 1; j < nma; j++)
3259                                     if (ma[j].cont_level == 0)
3260                                             break;
3261                                 v->nmagic = j - i;
3262                                 return 0;
3263                         }
3264                 }
3265         }
3266         return -1;
3267 }