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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
29 * softmagic - interpret variable magic from MAGIC
35 FILE_RCSID("@(#)$File: softmagic.c,v 1.249 2017/06/19 18:30:25 christos Exp $")
46 private int match(struct magic_set
*, struct magic
*, uint32_t,
47 const unsigned char *, size_t, size_t, int, int, int, uint16_t *,
48 uint16_t *, int *, int *, int *);
49 private int mget(struct magic_set
*, const unsigned char *,
50 struct magic
*, size_t, size_t, unsigned int, int, int, int, uint16_t *,
51 uint16_t *, int *, int *, int *);
52 private int magiccheck(struct magic_set
*, struct magic
*);
53 private int32_t mprint(struct magic_set
*, struct magic
*);
54 private int moffset(struct magic_set
*, struct magic
*, size_t, int32_t *);
55 private void mdebug(uint32_t, const char *, size_t);
56 private int mcopy(struct magic_set
*, union VALUETYPE
*, int, int,
57 const unsigned char *, uint32_t, size_t, struct magic
*);
58 private int mconvert(struct magic_set
*, struct magic
*, int);
59 private int print_sep(struct magic_set
*, int);
60 private int handle_annotation(struct magic_set
*, struct magic
*, int);
61 private int cvt_8(union VALUETYPE
*, const struct magic
*);
62 private int cvt_16(union VALUETYPE
*, const struct magic
*);
63 private int cvt_32(union VALUETYPE
*, const struct magic
*);
64 private int cvt_64(union VALUETYPE
*, const struct magic
*);
66 #define OFFSET_OOB(n, o, i) ((n) < (uint32_t)(o) || (i) > ((n) - (o)))
67 #define BE64(p) (((uint64_t)(p)->hq[0]<<56)|((uint64_t)(p)->hq[1]<<48)| \
68 ((uint64_t)(p)->hq[2]<<40)|((uint64_t)(p)->hq[3]<<32)| \
69 ((uint64_t)(p)->hq[4]<<24)|((uint64_t)(p)->hq[5]<<16)| \
70 ((uint64_t)(p)->hq[6]<<8)|((uint64_t)(p)->hq[7]))
71 #define LE64(p) (((uint64_t)(p)->hq[7]<<56)|((uint64_t)(p)->hq[6]<<48)| \
72 ((uint64_t)(p)->hq[5]<<40)|((uint64_t)(p)->hq[4]<<32)| \
73 ((uint64_t)(p)->hq[3]<<24)|((uint64_t)(p)->hq[2]<<16)| \
74 ((uint64_t)(p)->hq[1]<<8)|((uint64_t)(p)->hq[0]))
75 #define LE32(p) (((uint32_t)(p)->hl[3]<<24)|((uint32_t)(p)->hl[2]<<16)| \
76 ((uint32_t)(p)->hl[1]<<8)|((uint32_t)(p)->hl[0]))
77 #define BE32(p) (((uint32_t)(p)->hl[0]<<24)|((uint32_t)(p)->hl[1]<<16)| \
78 ((uint32_t)(p)->hl[2]<<8)|((uint32_t)(p)->hl[3]))
79 #define ME32(p) (((uint32_t)(p)->hl[1]<<24)|((uint32_t)(p)->hl[0]<<16)| \
80 ((uint32_t)(p)->hl[3]<<8)|((uint32_t)(p)->hl[2]))
81 #define BE16(p) (((uint16_t)(p)->hs[0]<<8)|((uint16_t)(p)->hs[1]))
82 #define LE16(p) (((uint16_t)(p)->hs[1]<<8)|((uint16_t)(p)->hs[0]))
83 #define SEXT(s,v,p) ((s)?(intmax_t)(int##v##_t)(p):(intmax_t)(uint##v##_t)(p))
86 * softmagic - lookup one file in parsed, in-memory copy of database
87 * Passed the name and FILE * of one file to be typed.
89 /*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
91 file_softmagic(struct magic_set
*ms
, const unsigned char *buf
, size_t nbytes
,
92 uint16_t *indir_count
, uint16_t *name_count
, int mode
, int text
)
95 int rv
, printed_something
= 0, need_separator
= 0;
98 if (name_count
== NULL
) {
102 if (indir_count
== NULL
) {
107 for (ml
= ms
->mlist
[0]->next
; ml
!= ms
->mlist
[0]; ml
= ml
->next
)
108 if ((rv
= match(ms
, ml
->magic
, ml
->nmagic
, buf
, nbytes
, 0, mode
,
109 text
, 0, indir_count
, name_count
,
110 &printed_something
, &need_separator
, NULL
)) != 0)
116 #define FILE_FMTDEBUG
118 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__)
120 private const char * __attribute__((__format_arg__(3)))
121 file_fmtcheck(struct magic_set
*ms
, const struct magic
*m
, const char *def
,
122 const char *file
, size_t line
)
124 const char *ptr
= fmtcheck(m
->desc
, def
);
127 "%s, %" SIZE_T_FORMAT
"u: format `%s' does not match"
128 " with `%s'", file
, line
, m
->desc
, def
);
132 #define F(a, b, c) fmtcheck((b)->desc, (c))
136 * Go through the whole list, stopping if you find a match. Process all
137 * the continuations of that match before returning.
139 * We support multi-level continuations:
141 * At any time when processing a successful top-level match, there is a
142 * current continuation level; it represents the level of the last
143 * successfully matched continuation.
145 * Continuations above that level are skipped as, if we see one, it
146 * means that the continuation that controls them - i.e, the
147 * lower-level continuation preceding them - failed to match.
149 * Continuations below that level are processed as, if we see one,
150 * it means we've finished processing or skipping higher-level
151 * continuations under the control of a successful or unsuccessful
152 * lower-level continuation, and are now seeing the next lower-level
153 * continuation and should process it. The current continuation
154 * level reverts to the level of the one we're seeing.
156 * Continuations at the current level are processed as, if we see
157 * one, there's no lower-level continuation that may have failed.
159 * If a continuation matches, we bump the current continuation level
160 * so that higher-level continuations are processed.
163 match(struct magic_set
*ms
, struct magic
*magic
, uint32_t nmagic
,
164 const unsigned char *s
, size_t nbytes
, size_t offset
, int mode
, int text
,
165 int flip
, uint16_t *indir_count
, uint16_t *name_count
,
166 int *printed_something
, int *need_separator
, int *returnval
)
168 uint32_t magindex
= 0;
169 unsigned int cont_level
= 0;
170 int returnvalv
= 0, e
; /* if a match is found it is set to 1*/
171 int firstline
= 1; /* a flag to print X\n X\n- X */
172 int print
= (ms
->flags
& MAGIC_NODESC
) == 0;
174 if (returnval
== NULL
)
175 returnval
= &returnvalv
;
177 if (file_check_mem(ms
, cont_level
) == -1)
180 for (magindex
= 0; magindex
< nmagic
; magindex
++) {
182 struct magic
*m
= &magic
[magindex
];
184 if (m
->type
!= FILE_NAME
)
185 if ((IS_STRING(m
->type
) &&
186 #define FLT (STRING_BINTEST | STRING_TEXTTEST)
187 ((text
&& (m
->str_flags
& FLT
) == STRING_BINTEST
) ||
188 (!text
&& (m
->str_flags
& FLT
) == STRING_TEXTTEST
))) ||
189 (m
->flag
& mode
) != mode
) {
192 while (magindex
< nmagic
- 1 &&
193 magic
[magindex
+ 1].cont_level
!= 0)
196 continue; /* Skip to next top-level test*/
199 ms
->offset
= m
->offset
;
200 ms
->line
= m
->lineno
;
202 /* if main entry matches, print it... */
203 switch (mget(ms
, s
, m
, nbytes
, offset
, cont_level
, mode
, text
,
204 flip
, indir_count
, name_count
,
205 printed_something
, need_separator
, returnval
)) {
209 flush
= m
->reln
!= '!';
212 if (m
->type
== FILE_INDIRECT
)
215 switch (magiccheck(ms
, m
)) {
229 * main entry didn't match,
230 * flush its continuations
235 if ((e
= handle_annotation(ms
, m
, firstline
)) != 0) {
237 *printed_something
= 1;
243 * If we are going to print something, we'll need to print
244 * a blank before we print something else.
248 *printed_something
= 1;
249 if (print_sep(ms
, firstline
) == -1)
254 if (print
&& mprint(ms
, m
) == -1)
257 switch (moffset(ms
, m
, nbytes
, &ms
->c
.li
[cont_level
].off
)) {
265 /* and any continuations that match */
266 if (file_check_mem(ms
, ++cont_level
) == -1)
269 while (magindex
+ 1 < nmagic
&&
270 magic
[magindex
+ 1].cont_level
!= 0) {
271 m
= &magic
[++magindex
];
272 ms
->line
= m
->lineno
; /* for messages */
274 if (cont_level
< m
->cont_level
)
276 if (cont_level
> m
->cont_level
) {
278 * We're at the end of the level
279 * "cont_level" continuations.
281 cont_level
= m
->cont_level
;
283 ms
->offset
= m
->offset
;
284 if (m
->flag
& OFFADD
) {
286 ms
->c
.li
[cont_level
- 1].off
;
289 #ifdef ENABLE_CONDITIONALS
290 if (m
->cond
== COND_ELSE
||
291 m
->cond
== COND_ELIF
) {
292 if (ms
->c
.li
[cont_level
].last_match
== 1)
296 switch (mget(ms
, s
, m
, nbytes
, offset
, cont_level
, mode
,
297 text
, flip
, indir_count
, name_count
,
298 printed_something
, need_separator
, returnval
)) {
307 if (m
->type
== FILE_INDIRECT
)
313 switch (flush
? 1 : magiccheck(ms
, m
)) {
317 #ifdef ENABLE_CONDITIONALS
318 ms
->c
.li
[cont_level
].last_match
= 0;
322 #ifdef ENABLE_CONDITIONALS
323 ms
->c
.li
[cont_level
].last_match
= 1;
325 if (m
->type
== FILE_CLEAR
)
326 ms
->c
.li
[cont_level
].got_match
= 0;
327 else if (ms
->c
.li
[cont_level
].got_match
) {
328 if (m
->type
== FILE_DEFAULT
)
331 ms
->c
.li
[cont_level
].got_match
= 1;
333 if ((e
= handle_annotation(ms
, m
, firstline
)) != 0) {
335 *printed_something
= 1;
340 * If we are going to print something,
341 * make sure that we have a separator first.
344 if (!*printed_something
) {
345 *printed_something
= 1;
346 if (print_sep(ms
, firstline
)
352 * This continuation matched. Print
353 * its message, with a blank before it
354 * if the previous item printed and
355 * this item isn't empty.
357 /* space if previous printed */
359 && ((m
->flag
& NOSPACE
) == 0)
362 file_printf(ms
, " ") == -1)
366 if (print
&& mprint(ms
, m
) == -1)
369 switch (moffset(ms
, m
, nbytes
,
370 &ms
->c
.li
[cont_level
].off
)) {
384 * If we see any continuations
388 if (file_check_mem(ms
, ++cont_level
) == -1)
393 if (*printed_something
) {
398 if ((ms
->flags
& MAGIC_CONTINUE
) == 0 && *printed_something
) {
399 return *returnval
; /* don't keep searching */
403 return *returnval
; /* This is hit if -k is set or there is no match */
407 check_fmt(struct magic_set
*ms
, struct magic
*m
)
412 if (strchr(m
->desc
, '%') == NULL
)
415 rc
= file_regcomp(&rx
, "%[-0-9\\.]*s", REG_EXTENDED
|REG_NOSUB
);
417 file_regerror(&rx
, rc
, ms
);
419 rc
= file_regexec(&rx
, m
->desc
, 0, 0, 0);
427 char * strndup(const char *, size_t);
430 strndup(const char *str
, size_t n
)
435 for (len
= 0; len
< n
&& str
[len
]; len
++)
437 if ((copy
= malloc(len
+ 1)) == NULL
)
439 (void)memcpy(copy
, str
, len
);
443 #endif /* HAVE_STRNDUP */
446 mprint(struct magic_set
*ms
, struct magic
*m
)
452 char buf
[128], tbuf
[26], sbuf
[512];
453 union VALUETYPE
*p
= &ms
->ms_value
;
457 v
= file_signextend(ms
, m
, (uint64_t)p
->b
);
458 switch (check_fmt(ms
, m
)) {
462 (void)snprintf(buf
, sizeof(buf
), "%d",
464 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
468 if (file_printf(ms
, F(ms
, m
, "%d"),
469 (unsigned char) v
) == -1)
473 t
= ms
->offset
+ sizeof(char);
479 v
= file_signextend(ms
, m
, (uint64_t)p
->h
);
480 switch (check_fmt(ms
, m
)) {
484 (void)snprintf(buf
, sizeof(buf
), "%u",
486 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
490 if (file_printf(ms
, F(ms
, m
, "%u"),
491 (unsigned short) v
) == -1)
495 t
= ms
->offset
+ sizeof(short);
502 v
= file_signextend(ms
, m
, (uint64_t)p
->l
);
503 switch (check_fmt(ms
, m
)) {
507 (void)snprintf(buf
, sizeof(buf
), "%u", (uint32_t) v
);
508 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
512 if (file_printf(ms
, F(ms
, m
, "%u"), (uint32_t) v
) == -1)
516 t
= ms
->offset
+ sizeof(int32_t);
522 v
= file_signextend(ms
, m
, p
->q
);
523 switch (check_fmt(ms
, m
)) {
527 (void)snprintf(buf
, sizeof(buf
), "%" INT64_T_FORMAT
"u",
528 (unsigned long long)v
);
529 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
533 if (file_printf(ms
, F(ms
, m
, "%" INT64_T_FORMAT
"u"),
534 (unsigned long long) v
) == -1)
538 t
= ms
->offset
+ sizeof(int64_t);
543 case FILE_BESTRING16
:
544 case FILE_LESTRING16
:
545 if (m
->reln
== '=' || m
->reln
== '!') {
546 if (file_printf(ms
, F(ms
, m
, "%s"),
547 file_printable(sbuf
, sizeof(sbuf
), m
->value
.s
))
550 t
= ms
->offset
+ m
->vallen
;
555 /* compute t before we mangle the string? */
556 t
= ms
->offset
+ strlen(str
);
558 if (*m
->value
.s
== '\0')
559 str
[strcspn(str
, "\r\n")] = '\0';
561 if (m
->str_flags
& STRING_TRIM
) {
563 while (isspace((unsigned char)*str
))
569 while (isspace((unsigned char)*last
))
574 if (file_printf(ms
, F(ms
, m
, "%s"),
575 file_printable(sbuf
, sizeof(sbuf
), str
)) == -1)
578 if (m
->type
== FILE_PSTRING
)
579 t
+= file_pstring_length_size(m
);
587 if (file_printf(ms
, F(ms
, m
, "%s"),
588 file_fmttime(p
->l
, 0, tbuf
)) == -1)
590 t
= ms
->offset
+ sizeof(uint32_t);
597 if (file_printf(ms
, F(ms
, m
, "%s"),
598 file_fmttime(p
->l
, FILE_T_LOCAL
, tbuf
)) == -1)
600 t
= ms
->offset
+ sizeof(uint32_t);
606 if (file_printf(ms
, F(ms
, m
, "%s"),
607 file_fmttime(p
->q
, 0, tbuf
)) == -1)
609 t
= ms
->offset
+ sizeof(uint64_t);
615 if (file_printf(ms
, F(ms
, m
, "%s"),
616 file_fmttime(p
->q
, FILE_T_LOCAL
, tbuf
)) == -1)
618 t
= ms
->offset
+ sizeof(uint64_t);
624 if (file_printf(ms
, F(ms
, m
, "%s"),
625 file_fmttime(p
->q
, FILE_T_WINDOWS
, tbuf
)) == -1)
627 t
= ms
->offset
+ sizeof(uint64_t);
634 switch (check_fmt(ms
, m
)) {
638 (void)snprintf(buf
, sizeof(buf
), "%g", vf
);
639 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
643 if (file_printf(ms
, F(ms
, m
, "%g"), vf
) == -1)
647 t
= ms
->offset
+ sizeof(float);
654 switch (check_fmt(ms
, m
)) {
658 (void)snprintf(buf
, sizeof(buf
), "%g", vd
);
659 if (file_printf(ms
, F(ms
, m
, "%s"), buf
) == -1)
663 if (file_printf(ms
, F(ms
, m
, "%g"), vd
) == -1)
667 t
= ms
->offset
+ sizeof(double);
675 cp
= strndup((const char *)ms
->search
.s
, ms
->search
.rm_len
);
677 file_oomem(ms
, ms
->search
.rm_len
);
680 rval
= file_printf(ms
, F(ms
, m
, "%s"),
681 file_printable(sbuf
, sizeof(sbuf
), cp
));
687 if ((m
->str_flags
& REGEX_OFFSET_START
))
688 t
= ms
->search
.offset
;
690 t
= ms
->search
.offset
+ ms
->search
.rm_len
;
696 if (file_printf(ms
, "%s", m
->desc
) == -1)
707 if (file_printf(ms
, F(ms
, m
, "%s"),
708 file_printable(sbuf
, sizeof(sbuf
), ms
->ms_value
.s
)) == -1)
713 file_magerror(ms
, "invalid m->type (%d) in mprint()", m
->type
);
720 moffset(struct magic_set
*ms
, struct magic
*m
, size_t nbytes
, int32_t *op
)
726 o
= CAST(int32_t, (ms
->offset
+ sizeof(char)));
732 o
= CAST(int32_t, (ms
->offset
+ sizeof(short)));
739 o
= CAST(int32_t, (ms
->offset
+ sizeof(int32_t)));
745 o
= CAST(int32_t, (ms
->offset
+ sizeof(int64_t)));
750 case FILE_BESTRING16
:
751 case FILE_LESTRING16
:
752 if (m
->reln
== '=' || m
->reln
== '!') {
753 o
= ms
->offset
+ m
->vallen
;
755 union VALUETYPE
*p
= &ms
->ms_value
;
757 if (*m
->value
.s
== '\0')
758 p
->s
[strcspn(p
->s
, "\r\n")] = '\0';
759 o
= CAST(uint32_t, (ms
->offset
+ strlen(p
->s
)));
760 if (m
->type
== FILE_PSTRING
)
761 o
+= (uint32_t)file_pstring_length_size(m
);
769 o
= CAST(int32_t, (ms
->offset
+ sizeof(uint32_t)));
776 o
= CAST(int32_t, (ms
->offset
+ sizeof(uint32_t)));
782 o
= CAST(int32_t, (ms
->offset
+ sizeof(uint64_t)));
788 o
= CAST(int32_t, (ms
->offset
+ sizeof(uint64_t)));
794 o
= CAST(int32_t, (ms
->offset
+ sizeof(float)));
800 o
= CAST(int32_t, (ms
->offset
+ sizeof(double)));
804 if ((m
->str_flags
& REGEX_OFFSET_START
) != 0)
805 o
= CAST(int32_t, ms
->search
.offset
);
808 (ms
->search
.offset
+ ms
->search
.rm_len
));
812 if ((m
->str_flags
& REGEX_OFFSET_START
) != 0)
813 o
= CAST(int32_t, ms
->search
.offset
);
815 o
= CAST(int32_t, (ms
->search
.offset
+ m
->vallen
));
826 o
= der_offs(ms
, m
, nbytes
);
827 if (o
== -1 || (size_t)o
> nbytes
) {
828 if ((ms
->flags
& MAGIC_DEBUG
) != 0) {
829 (void)fprintf(stderr
,
830 "Bad DER offset %d nbytes=%zu",
844 if ((size_t)o
> nbytes
) {
846 file_error(ms
, 0, "Offset out of range %zu > %zu",
856 cvt_id3(struct magic_set
*ms
, uint32_t v
)
858 v
= ((((v
>> 0) & 0x7f) << 0) |
859 (((v
>> 8) & 0x7f) << 7) |
860 (((v
>> 16) & 0x7f) << 14) |
861 (((v
>> 24) & 0x7f) << 21));
862 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
863 fprintf(stderr
, "id3 offs=%u\n", v
);
868 cvt_flip(int type
, int flip
)
886 return FILE_LEQLDATE
;
888 return FILE_LEQWDATE
;
902 return FILE_BEQLDATE
;
904 return FILE_BEQWDATE
;
910 return FILE_LEDOUBLE
;
912 return FILE_BEDOUBLE
;
917 #define DO_CVT(fld, cast) \
919 switch (m->mask_op & FILE_OPS_MASK) { \
921 p->fld &= cast m->num_mask; \
924 p->fld |= cast m->num_mask; \
927 p->fld ^= cast m->num_mask; \
930 p->fld += cast m->num_mask; \
933 p->fld -= cast m->num_mask; \
935 case FILE_OPMULTIPLY: \
936 p->fld *= cast m->num_mask; \
938 case FILE_OPDIVIDE: \
939 if (cast m->num_mask == 0) \
941 p->fld /= cast m->num_mask; \
943 case FILE_OPMODULO: \
944 if (cast m->num_mask == 0) \
946 p->fld %= cast m->num_mask; \
949 if (m->mask_op & FILE_OPINVERSE) \
953 cvt_8(union VALUETYPE
*p
, const struct magic
*m
)
955 DO_CVT(b
, (uint8_t));
960 cvt_16(union VALUETYPE
*p
, const struct magic
*m
)
962 DO_CVT(h
, (uint16_t));
967 cvt_32(union VALUETYPE
*p
, const struct magic
*m
)
969 DO_CVT(l
, (uint32_t));
974 cvt_64(union VALUETYPE
*p
, const struct magic
*m
)
976 DO_CVT(q
, (uint64_t));
980 #define DO_CVT2(fld, cast) \
982 switch (m->mask_op & FILE_OPS_MASK) { \
984 p->fld += cast m->num_mask; \
987 p->fld -= cast m->num_mask; \
989 case FILE_OPMULTIPLY: \
990 p->fld *= cast m->num_mask; \
992 case FILE_OPDIVIDE: \
993 if (cast m->num_mask == 0) \
995 p->fld /= cast m->num_mask; \
1000 cvt_float(union VALUETYPE
*p
, const struct magic
*m
)
1002 DO_CVT2(f
, (float));
1007 cvt_double(union VALUETYPE
*p
, const struct magic
*m
)
1009 DO_CVT2(d
, (double));
1014 * Convert the byte order of the data we are looking at
1015 * While we're here, let's apply the mask operation
1016 * (unless you have a better idea)
1019 mconvert(struct magic_set
*ms
, struct magic
*m
, int flip
)
1021 union VALUETYPE
*p
= &ms
->ms_value
;
1023 switch (cvt_flip(m
->type
, flip
)) {
1025 if (cvt_8(p
, m
) == -1)
1029 if (cvt_16(p
, m
) == -1)
1035 if (cvt_32(p
, m
) == -1)
1042 if (cvt_64(p
, m
) == -1)
1046 case FILE_BESTRING16
:
1047 case FILE_LESTRING16
: {
1048 /* Null terminate and eat *trailing* return */
1049 p
->s
[sizeof(p
->s
) - 1] = '\0';
1052 case FILE_PSTRING
: {
1053 size_t sz
= file_pstring_length_size(m
);
1054 char *ptr1
= p
->s
, *ptr2
= ptr1
+ sz
;
1055 size_t len
= file_pstring_get_length(m
, ptr1
);
1056 sz
= sizeof(p
->s
) - sz
; /* maximum length of string */
1059 * The size of the pascal string length (sz)
1060 * is 1, 2, or 4. We need at least 1 byte for NUL
1061 * termination, but we've already truncated the
1062 * string by p->s, so we need to deduct sz.
1063 * Because we can use one of the bytes of the length
1064 * after we shifted as NUL termination.
1074 p
->h
= (short)BE16(p
);
1075 if (cvt_16(p
, m
) == -1)
1081 p
->l
= (int32_t)BE32(p
);
1082 if (cvt_32(p
, m
) == -1)
1089 p
->q
= (uint64_t)BE64(p
);
1090 if (cvt_64(p
, m
) == -1)
1094 p
->h
= (short)LE16(p
);
1095 if (cvt_16(p
, m
) == -1)
1101 p
->l
= (int32_t)LE32(p
);
1102 if (cvt_32(p
, m
) == -1)
1109 p
->q
= (uint64_t)LE64(p
);
1110 if (cvt_64(p
, m
) == -1)
1116 p
->l
= (int32_t)ME32(p
);
1117 if (cvt_32(p
, m
) == -1)
1121 if (cvt_float(p
, m
) == -1)
1126 if (cvt_float(p
, m
) == -1)
1131 if (cvt_float(p
, m
) == -1)
1135 if (cvt_double(p
, m
) == -1)
1140 if (cvt_double(p
, m
) == -1)
1145 if (cvt_double(p
, m
) == -1)
1157 file_magerror(ms
, "invalid type %d in mconvert()", m
->type
);
1161 file_magerror(ms
, "zerodivide in mconvert()");
1167 mdebug(uint32_t offset
, const char *str
, size_t len
)
1169 (void) fprintf(stderr
, "mget/%" SIZE_T_FORMAT
"u @%d: ", len
, offset
);
1170 file_showstr(stderr
, str
, len
);
1171 (void) fputc('\n', stderr
);
1172 (void) fputc('\n', stderr
);
1176 mcopy(struct magic_set
*ms
, union VALUETYPE
*p
, int type
, int indir
,
1177 const unsigned char *s
, uint32_t offset
, size_t nbytes
, struct magic
*m
)
1180 * Note: FILE_SEARCH and FILE_REGEX do not actually copy
1181 * anything, but setup pointers into the source
1187 if (offset
> nbytes
)
1188 offset
= CAST(uint32_t, nbytes
);
1189 ms
->search
.s
= RCAST(const char *, s
) + offset
;
1190 ms
->search
.s_len
= nbytes
- offset
;
1191 ms
->search
.offset
= offset
;
1197 const char *last
; /* end of search region */
1198 const char *buf
; /* start of search region */
1200 size_t lines
, linecnt
, bytecnt
;
1202 if (s
== NULL
|| nbytes
< offset
) {
1203 ms
->search
.s_len
= 0;
1204 ms
->search
.s
= NULL
;
1208 if (m
->str_flags
& REGEX_LINE_COUNT
) {
1209 linecnt
= m
->str_range
;
1210 bytecnt
= linecnt
* 80;
1213 bytecnt
= m
->str_range
;
1216 if (bytecnt
== 0 || bytecnt
> nbytes
- offset
)
1217 bytecnt
= nbytes
- offset
;
1218 if (bytecnt
> ms
->regex_max
)
1219 bytecnt
= ms
->regex_max
;
1221 buf
= RCAST(const char *, s
) + offset
;
1222 end
= last
= RCAST(const char *, s
) + bytecnt
+ offset
;
1223 /* mget() guarantees buf <= last */
1224 for (lines
= linecnt
, b
= buf
; lines
&& b
< end
&&
1225 ((b
= CAST(const char *,
1226 memchr(c
= b
, '\n', CAST(size_t, (end
- b
)))))
1227 || (b
= CAST(const char *,
1228 memchr(c
, '\r', CAST(size_t, (end
- c
))))));
1231 if (b
< end
- 1 && b
[0] == '\r' && b
[1] == '\n')
1235 last
= RCAST(const char *, s
) + bytecnt
;
1238 ms
->search
.s_len
= last
- buf
;
1239 ms
->search
.offset
= offset
;
1240 ms
->search
.rm_len
= 0;
1243 case FILE_BESTRING16
:
1244 case FILE_LESTRING16
: {
1245 const unsigned char *src
= s
+ offset
;
1246 const unsigned char *esrc
= s
+ nbytes
;
1248 char *edst
= &p
->s
[sizeof(p
->s
) - 1];
1250 if (type
== FILE_BESTRING16
)
1253 /* check that offset is within range */
1254 if (offset
>= nbytes
)
1256 for (/*EMPTY*/; src
< esrc
; src
+= 2, dst
++) {
1262 if (type
== FILE_BESTRING16
?
1263 *(src
- 1) != '\0' :
1264 ((src
+ 1 < esrc
) &&
1265 *(src
+ 1) != '\0'))
1272 case FILE_STRING
: /* XXX - these two should not need */
1273 case FILE_PSTRING
: /* to copy anything, but do anyway. */
1279 if (offset
>= nbytes
) {
1280 (void)memset(p
, '\0', sizeof(*p
));
1283 if (nbytes
- offset
< sizeof(*p
))
1284 nbytes
= nbytes
- offset
;
1286 nbytes
= sizeof(*p
);
1288 (void)memcpy(p
, s
+ offset
, nbytes
);
1291 * the usefulness of padding with zeroes eludes me, it
1292 * might even cause problems
1294 if (nbytes
< sizeof(*p
))
1295 (void)memset(((char *)(void *)p
) + nbytes
, '\0',
1296 sizeof(*p
) - nbytes
);
1301 do_ops(struct magic
*m
, intmax_t lhs
, intmax_t off
)
1303 intmax_t offset
= 0;
1305 switch (m
->in_op
& FILE_OPS_MASK
) {
1321 case FILE_OPMULTIPLY
:
1333 if (m
->in_op
& FILE_OPINVERSE
)
1336 return (uint32_t)offset
;
1340 mget(struct magic_set
*ms
, const unsigned char *s
, struct magic
*m
,
1341 size_t nbytes
, size_t o
, unsigned int cont_level
, int mode
, int text
,
1342 int flip
, uint16_t *indir_count
, uint16_t *name_count
,
1343 int *printed_something
, int *need_separator
, int *returnval
)
1345 uint32_t offset
= ms
->offset
;
1348 int rv
, oneed_separator
, in_type
;
1350 union VALUETYPE
*p
= &ms
->ms_value
;
1353 if (*indir_count
>= ms
->indir_max
) {
1354 file_error(ms
, 0, "indirect count (%hu) exceeded",
1359 if (*name_count
>= ms
->name_max
) {
1360 file_error(ms
, 0, "name use count (%hu) exceeded",
1365 if (mcopy(ms
, p
, m
->type
, m
->flag
& INDIR
, s
, (uint32_t)(offset
+ o
),
1366 (uint32_t)nbytes
, m
) == -1)
1369 if ((ms
->flags
& MAGIC_DEBUG
) != 0) {
1370 fprintf(stderr
, "mget(type=%d, flag=%#x, offset=%u, o=%"
1371 SIZE_T_FORMAT
"u, " "nbytes=%" SIZE_T_FORMAT
1372 "u, il=%hu, nc=%hu)\n",
1373 m
->type
, m
->flag
, offset
, o
, nbytes
,
1374 *indir_count
, *name_count
);
1375 mdebug(offset
, (char *)(void *)p
, sizeof(union VALUETYPE
));
1376 #ifndef COMPILE_ONLY
1381 if (m
->flag
& INDIR
) {
1382 intmax_t off
= m
->in_offset
;
1383 const int sgn
= m
->in_op
& FILE_OPSIGNED
;
1384 if (m
->in_op
& FILE_OPINDIRECT
) {
1385 const union VALUETYPE
*q
= CAST(const union VALUETYPE
*,
1386 ((const void *)(s
+ offset
+ off
)));
1387 if (OFFSET_OOB(nbytes
, offset
+ off
, sizeof(*q
)))
1389 switch (cvt_flip(m
->in_type
, flip
)) {
1391 off
= SEXT(sgn
,8,q
->b
);
1394 off
= SEXT(sgn
,16,q
->h
);
1397 off
= SEXT(sgn
,16,BE16(q
));
1400 off
= SEXT(sgn
,16,LE16(q
));
1403 off
= SEXT(sgn
,32,q
->l
);
1407 off
= SEXT(sgn
,32,BE32(q
));
1411 off
= SEXT(sgn
,32,LE32(q
));
1414 off
= SEXT(sgn
,32,ME32(q
));
1417 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1418 fprintf(stderr
, "indirect offs=%jd\n", off
);
1420 switch (in_type
= cvt_flip(m
->in_type
, flip
)) {
1422 if (OFFSET_OOB(nbytes
, offset
, 1))
1424 offset
= do_ops(m
, SEXT(sgn
,8,p
->b
), off
);
1427 if (OFFSET_OOB(nbytes
, offset
, 2))
1429 offset
= do_ops(m
, SEXT(sgn
,16,BE16(p
)), off
);
1432 if (OFFSET_OOB(nbytes
, offset
, 2))
1434 offset
= do_ops(m
, SEXT(sgn
,16,LE16(p
)), off
);
1437 if (OFFSET_OOB(nbytes
, offset
, 2))
1439 offset
= do_ops(m
, SEXT(sgn
,16,p
->h
), off
);
1443 if (OFFSET_OOB(nbytes
, offset
, 4))
1446 if (in_type
== FILE_BEID3
)
1447 lhs
= cvt_id3(ms
, (uint32_t)lhs
);
1448 offset
= do_ops(m
, SEXT(sgn
,32,lhs
), off
);
1452 if (OFFSET_OOB(nbytes
, offset
, 4))
1455 if (in_type
== FILE_LEID3
)
1456 lhs
= cvt_id3(ms
, (uint32_t)lhs
);
1457 offset
= do_ops(m
, SEXT(sgn
,32,lhs
), off
);
1460 if (OFFSET_OOB(nbytes
, offset
, 4))
1462 offset
= do_ops(m
, SEXT(sgn
,32,ME32(p
)), off
);
1465 if (OFFSET_OOB(nbytes
, offset
, 4))
1467 offset
= do_ops(m
, SEXT(sgn
,32,p
->l
), off
);
1473 if (m
->flag
& INDIROFFADD
) {
1474 offset
+= ms
->c
.li
[cont_level
-1].off
;
1476 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1478 "indirect *zero* offset\n");
1481 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1482 fprintf(stderr
, "indirect +offs=%u\n", offset
);
1484 if (mcopy(ms
, p
, m
->type
, 0, s
, offset
, nbytes
, m
) == -1)
1486 ms
->offset
= offset
;
1488 if ((ms
->flags
& MAGIC_DEBUG
) != 0) {
1489 mdebug(offset
, (char *)(void *)p
,
1490 sizeof(union VALUETYPE
));
1491 #ifndef COMPILE_ONLY
1497 /* Verify we have enough data to match magic type */
1500 if (OFFSET_OOB(nbytes
, offset
, 1))
1507 if (OFFSET_OOB(nbytes
, offset
, 2))
1526 if (OFFSET_OOB(nbytes
, offset
, 4))
1533 if (OFFSET_OOB(nbytes
, offset
, 8))
1540 if (OFFSET_OOB(nbytes
, offset
, m
->vallen
))
1545 if (nbytes
< offset
)
1550 if (m
->str_flags
& INDIRECT_RELATIVE
)
1551 offset
+= CAST(uint32_t, o
);
1555 if (nbytes
< offset
)
1558 if ((pb
= file_push_buffer(ms
)) == NULL
)
1562 rv
= file_softmagic(ms
, s
+ offset
, nbytes
- offset
,
1563 indir_count
, name_count
, BINTEST
, text
);
1565 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1566 fprintf(stderr
, "indirect @offs=%u[%d]\n", offset
, rv
);
1568 rbuf
= file_pop_buffer(ms
, pb
);
1569 if (rbuf
== NULL
&& ms
->event_flags
& EVENT_HAD_ERR
)
1573 if ((ms
->flags
& MAGIC_NODESC
) == 0 &&
1574 file_printf(ms
, F(ms
, m
, "%u"), offset
) == -1) {
1578 if (file_printf(ms
, "%s", rbuf
) == -1) {
1587 if (nbytes
< offset
)
1594 if (file_magicfind(ms
, rbuf
, &ml
) == -1) {
1595 file_error(ms
, 0, "cannot find entry `%s'", rbuf
);
1599 oneed_separator
= *need_separator
;
1600 if (m
->flag
& NOSPACE
)
1601 *need_separator
= 0;
1602 rv
= match(ms
, ml
.magic
, ml
.nmagic
, s
, nbytes
, offset
+ o
,
1603 mode
, text
, flip
, indir_count
, name_count
,
1604 printed_something
, need_separator
, returnval
);
1606 *need_separator
= oneed_separator
;
1610 if (ms
->flags
& MAGIC_NODESC
)
1612 if (file_printf(ms
, "%s", m
->desc
) == -1)
1616 case FILE_DEFAULT
: /* nothing to check */
1621 if (!mconvert(ms
, m
, flip
))
1627 file_strncmp(const char *s1
, const char *s2
, size_t len
, uint32_t flags
)
1630 * Convert the source args to unsigned here so that (1) the
1631 * compare will be unsigned as it is in strncmp() and (2) so
1632 * the ctype functions will work correctly without extra
1635 const unsigned char *a
= (const unsigned char *)s1
;
1636 const unsigned char *b
= (const unsigned char *)s2
;
1637 const unsigned char *eb
= b
+ len
;
1641 * What we want here is v = strncmp(s1, s2, len),
1642 * but ignoring any nulls.
1645 if (0L == flags
) { /* normal string: do it fast */
1647 if ((v
= *b
++ - *a
++) != '\0')
1650 else { /* combine the others */
1656 if ((flags
& STRING_IGNORE_LOWERCASE
) &&
1658 if ((v
= tolower(*b
++) - *a
++) != '\0')
1661 else if ((flags
& STRING_IGNORE_UPPERCASE
) &&
1663 if ((v
= toupper(*b
++) - *a
++) != '\0')
1666 else if ((flags
& STRING_COMPACT_WHITESPACE
) &&
1669 if (isspace(*b
++)) {
1671 while (b
< eb
&& isspace(*b
))
1679 else if ((flags
& STRING_COMPACT_OPTIONAL_WHITESPACE
) &&
1682 while (b
< eb
&& isspace(*b
))
1686 if ((v
= *b
++ - *a
++) != '\0')
1695 file_strncmp16(const char *a
, const char *b
, size_t len
, uint32_t flags
)
1698 * XXX - The 16-bit string compare probably needs to be done
1699 * differently, especially if the flags are to be supported.
1700 * At the moment, I am unsure.
1703 return file_strncmp(a
, b
, len
, flags
);
1707 magiccheck(struct magic_set
*ms
, struct magic
*m
)
1709 uint64_t l
= m
->value
.q
;
1714 union VALUETYPE
*p
= &ms
->ms_value
;
1784 file_magerror(ms
, "cannot happen with float: invalid relation `%c'",
1817 file_magerror(ms
, "cannot happen with double: invalid relation `%c'", m
->reln
);
1831 v
= file_strncmp(m
->value
.s
, p
->s
, (size_t)m
->vallen
, m
->str_flags
);
1834 case FILE_BESTRING16
:
1835 case FILE_LESTRING16
:
1837 v
= file_strncmp16(m
->value
.s
, p
->s
, (size_t)m
->vallen
, m
->str_flags
);
1840 case FILE_SEARCH
: { /* search ms->search.s for the string m->value.s */
1844 if (ms
->search
.s
== NULL
)
1847 slen
= MIN(m
->vallen
, sizeof(m
->value
.s
));
1851 for (idx
= 0; m
->str_range
== 0 || idx
< m
->str_range
; idx
++) {
1852 if (slen
+ idx
> ms
->search
.s_len
)
1855 v
= file_strncmp(m
->value
.s
, ms
->search
.s
+ idx
, slen
,
1857 if (v
== 0) { /* found match */
1858 ms
->search
.offset
+= idx
;
1859 ms
->search
.rm_len
= ms
->search
.s_len
- idx
;
1870 if (ms
->search
.s
== NULL
)
1874 rc
= file_regcomp(&rx
, m
->value
.s
,
1875 REG_EXTENDED
|REG_NEWLINE
|
1876 ((m
->str_flags
& STRING_IGNORE_CASE
) ? REG_ICASE
: 0));
1878 file_regerror(&rx
, rc
, ms
);
1882 size_t slen
= ms
->search
.s_len
;
1885 copy
= CAST(char *, malloc(slen
));
1888 file_error(ms
, errno
,
1889 "can't allocate %" SIZE_T_FORMAT
"u bytes",
1893 memcpy(copy
, ms
->search
.s
, slen
);
1894 copy
[--slen
] = '\0';
1897 search
= CCAST(char *, "");
1900 rc
= file_regexec(&rx
, (const char *)search
,
1905 ms
->search
.s
+= (int)pmatch
.rm_so
;
1906 ms
->search
.offset
+= (size_t)pmatch
.rm_so
;
1908 (size_t)(pmatch
.rm_eo
- pmatch
.rm_so
);
1917 file_regerror(&rx
, rc
, ms
);
1923 if (v
== (uint64_t)-1)
1932 matched
= der_cmp(ms
, m
);
1933 if (matched
== -1) {
1934 if ((ms
->flags
& MAGIC_DEBUG
) != 0) {
1935 (void) fprintf(stderr
,
1936 "EOF comparing DER entries");
1942 file_magerror(ms
, "invalid type %d in magiccheck()", m
->type
);
1946 v
= file_signextend(ms
, m
, v
);
1950 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1951 (void) fprintf(stderr
, "%" INT64_T_FORMAT
1952 "u == *any* = 1\n", (unsigned long long)v
);
1958 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1959 (void) fprintf(stderr
, "%" INT64_T_FORMAT
"u != %"
1960 INT64_T_FORMAT
"u = %d\n", (unsigned long long)v
,
1961 (unsigned long long)l
, matched
);
1966 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1967 (void) fprintf(stderr
, "%" INT64_T_FORMAT
"u == %"
1968 INT64_T_FORMAT
"u = %d\n", (unsigned long long)v
,
1969 (unsigned long long)l
, matched
);
1973 if (m
->flag
& UNSIGNED
) {
1975 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1976 (void) fprintf(stderr
, "%" INT64_T_FORMAT
1977 "u > %" INT64_T_FORMAT
"u = %d\n",
1978 (unsigned long long)v
,
1979 (unsigned long long)l
, matched
);
1982 matched
= (int64_t) v
> (int64_t) l
;
1983 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1984 (void) fprintf(stderr
, "%" INT64_T_FORMAT
1985 "d > %" INT64_T_FORMAT
"d = %d\n",
1986 (long long)v
, (long long)l
, matched
);
1991 if (m
->flag
& UNSIGNED
) {
1993 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
1994 (void) fprintf(stderr
, "%" INT64_T_FORMAT
1995 "u < %" INT64_T_FORMAT
"u = %d\n",
1996 (unsigned long long)v
,
1997 (unsigned long long)l
, matched
);
2000 matched
= (int64_t) v
< (int64_t) l
;
2001 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
2002 (void) fprintf(stderr
, "%" INT64_T_FORMAT
2003 "d < %" INT64_T_FORMAT
"d = %d\n",
2004 (long long)v
, (long long)l
, matched
);
2009 matched
= (v
& l
) == l
;
2010 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
2011 (void) fprintf(stderr
, "((%" INT64_T_FORMAT
"x & %"
2012 INT64_T_FORMAT
"x) == %" INT64_T_FORMAT
2013 "x) = %d\n", (unsigned long long)v
,
2014 (unsigned long long)l
, (unsigned long long)l
,
2019 matched
= (v
& l
) != l
;
2020 if ((ms
->flags
& MAGIC_DEBUG
) != 0)
2021 (void) fprintf(stderr
, "((%" INT64_T_FORMAT
"x & %"
2022 INT64_T_FORMAT
"x) != %" INT64_T_FORMAT
2023 "x) = %d\n", (unsigned long long)v
,
2024 (unsigned long long)l
, (unsigned long long)l
,
2029 file_magerror(ms
, "cannot happen: invalid relation `%c'",
2038 handle_annotation(struct magic_set
*ms
, struct magic
*m
, int firstline
)
2040 if ((ms
->flags
& MAGIC_APPLE
) && m
->apple
[0]) {
2041 if (!firstline
&& file_printf(ms
, "\n- ") == -1)
2043 if (file_printf(ms
, "%.8s", m
->apple
) == -1)
2047 if ((ms
->flags
& MAGIC_EXTENSION
) && m
->ext
[0]) {
2048 if (!firstline
&& file_printf(ms
, "\n- ") == -1)
2050 if (file_printf(ms
, "%s", m
->ext
) == -1)
2054 if ((ms
->flags
& MAGIC_MIME_TYPE
) && m
->mimetype
[0]) {
2055 if (!firstline
&& file_printf(ms
, "\n- ") == -1)
2057 if (file_printf(ms
, "%s", m
->mimetype
) == -1)
2065 print_sep(struct magic_set
*ms
, int firstline
)
2067 // if (ms->flags & MAGIC_NODESC)
2072 * we found another match
2073 * put a newline and '-' to do some simple formatting
2075 return file_printf(ms
, "\n- ");