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