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