/* * Read a numeric value from a pointer, into the value union of a magic * pointer, according to the magic type. Update the string pointer to point * just after the number read. Return 0 for success, non-zero for failure. */ static int getvalue(RMagic *ms, struct r_magic *m, const char **p, int action) { int slen; switch (m->type) { case FILE_BESTRING16: case FILE_LESTRING16: case FILE_STRING: case FILE_PSTRING: case FILE_REGEX: case FILE_SEARCH: *p = getstr(ms, *p, m->value.s, sizeof (m->value.s), &slen, action); if (!*p) { if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "cannot get string from `%s'", m->value.s); return -1; } m->vallen = slen; if (m->type == FILE_PSTRING) m->vallen++; return 0; case FILE_FLOAT: case FILE_BEFLOAT: case FILE_LEFLOAT: if (m->reln != 'x') { char *ep; #ifdef HAVE_STRTOF m->value.f = strtof(*p, &ep); #else m->value.f = (float)strtod(*p, &ep); #endif *p = ep; } return 0; case FILE_DOUBLE: case FILE_BEDOUBLE: case FILE_LEDOUBLE: if (m->reln != 'x') { char *ep; m->value.d = strtod(*p, &ep); *p = ep; } return 0; default: if (m->reln != 'x') { char *ep; m->value.q = file_signextend(ms, m, (ut64)strtoull(*p, &ep, 0)); *p = ep; eatsize(p); } return 0; } }
/* * Read a numeric value from a pointer, into the value union of a magic * pointer, according to the magic type. Update the string pointer to point * just after the number read. Return 0 for success, non-zero for failure. */ static int getvalue(struct magic *m, char **p) { int slen; if (m->type == STRING) { *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen); m->vallen = slen; } else if (m->reln != 'x') { m->value.l = signextend(m, strtoul(*p, p, 0)); eatsize(p); } return (0); }
/* * parse one line from magic file, put into magic[index++] if valid */ static int parse(RMagic *ms, struct r_magic_entry **mentryp, ut32 *nmentryp, const char *line, size_t lineno, int action) { static ut32 last_cont_level = 0; size_t i; struct r_magic_entry *me; struct r_magic *m; const char *l = line; char *t; int op; ut32 cont_level = 0; for (; *l == '>'; l++, cont_level++); if (cont_level == 0 || cont_level > last_cont_level) if (file_check_mem (ms, cont_level) == -1) return -1; last_cont_level = cont_level; #define ALLOC_CHUNK (size_t)10 #define ALLOC_INCR (size_t)200 if (cont_level != 0) { if (*nmentryp == 0) { file_error(ms, 0, "No current entry for continuation"); return -1; } me = &(*mentryp)[*nmentryp - 1]; if (me->cont_count == me->max_count) { struct r_magic *nm; size_t cnt = me->max_count + ALLOC_CHUNK; if (!(nm = realloc(me->mp, sizeof (*nm) * cnt))) { file_oomem(ms, sizeof (*nm) * cnt); return -1; } me->mp = nm; me->max_count = cnt; } m = &me->mp[me->cont_count++]; (void)memset(m, 0, sizeof (*m)); m->cont_level = cont_level; } else { if (*nmentryp == maxmagic) { struct r_magic_entry *mp; maxmagic += ALLOC_INCR; if (!(mp = realloc (*mentryp, sizeof (*mp) * maxmagic))) { file_oomem (ms, sizeof (*mp) * maxmagic); return -1; } (void)memset(&mp[*nmentryp], 0, sizeof (*mp) * ALLOC_INCR); *mentryp = mp; } me = &(*mentryp)[*nmentryp]; if (!me->mp) { if (!(m = malloc (sizeof (*m) * ALLOC_CHUNK))) { file_oomem (ms, sizeof (*m) * ALLOC_CHUNK); return -1; } me->mp = m; me->max_count = ALLOC_CHUNK; } else m = me->mp; (void)memset(m, 0, sizeof (*m)); m->cont_level = 0; me->cont_count = 1; } m->lineno = lineno; if (*l == '&') { /* m->cont_level == 0 checked below. */ ++l; /* step over */ m->flag |= OFFADD; } if (*l == '(') { ++l; /* step over */ m->flag |= INDIR; if (m->flag & OFFADD) m->flag = (m->flag & ~OFFADD) | INDIROFFADD; if (*l == '&') { /* m->cont_level == 0 checked below */ ++l; /* step over */ m->flag |= OFFADD; } } /* Indirect offsets are not valid at level 0. */ if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD))) if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "relative offset at level 0"); /* get offset, then skip over it */ m->offset = (ut32)strtoul(l, &t, 0); if ((l == t) && (ms->flags & R_MAGIC_CHECK)) file_magwarn(ms, "offset `%s' invalid", l); l = t; if (m->flag & INDIR) { m->in_type = FILE_LONG; m->in_offset = 0; /* * read [.lbs][+-]nnnnn) */ if (*l == '.') { l++; switch (*l) { case 'l': m->in_type = FILE_LELONG; break; case 'L': m->in_type = FILE_BELONG; break; case 'm': m->in_type = FILE_MELONG; break; case 'h': case 's': m->in_type = FILE_LESHORT; break; case 'H': case 'S': m->in_type = FILE_BESHORT; break; case 'c': case 'b': case 'C': case 'B': m->in_type = FILE_BYTE; break; case 'e': case 'f': case 'g': m->in_type = FILE_LEDOUBLE; break; case 'E': case 'F': case 'G': m->in_type = FILE_BEDOUBLE; break; default: if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "indirect offset type `%c' invalid", *l); break; } l++; } m->in_op = 0; if (*l == '~') { m->in_op |= FILE_OPINVERSE; l++; } if ((op = get_op(*l)) != -1) { m->in_op |= op; l++; } if (*l == '(') { m->in_op |= FILE_OPINDIRECT; l++; } if (isdigit((ut8)*l) || *l == '-') { m->in_offset = (int32_t)strtol(l, &t, 0); if (l == t) if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "in_offset `%s' invalid", l); l = t; } if (*l++ != ')' || ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "missing ')' in indirect offset"); } EATAB; m->cond = get_cond(l, &l); if (check_cond(ms, m->cond, cont_level) == -1) return -1; EATAB; if (*l == 'u') { ++l; m->flag |= UNSIGNED; } m->type = get_type(l, &l); if (m->type == FILE_INVALID) { if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "type `%s' invalid", l); return -1; } /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */ /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */ m->mask_op = 0; if (*l == '~') { if (!MAGIC_IS_STRING (m->type)) m->mask_op |= FILE_OPINVERSE; else if (ms->flags & R_MAGIC_CHECK) file_magwarn (ms, "'~' invalid for string types"); ++l; } m->str_range = 0; m->str_flags = 0; m->num_mask = 0; if ((op = get_op (*l)) != -1) { if (!MAGIC_IS_STRING (m->type)) { ut64 val; ++l; m->mask_op |= op; val = (ut64)strtoull (l, &t, 0); l = t; m->num_mask = file_signextend (ms, m, val); eatsize (&l); } else if (op == FILE_OPDIVIDE) { int have_range = 0; while (!isspace ((ut8)*++l)) { switch (*l) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (have_range && (ms->flags & R_MAGIC_CHECK)) file_magwarn(ms, "multiple ranges"); have_range = 1; m->str_range = strtoul(l, &t, 0); if (m->str_range == 0) file_magwarn(ms, "zero range"); l = t - 1; break; case CHAR_COMPACT_BLANK: m->str_flags |= STRING_COMPACT_BLANK; break; case CHAR_COMPACT_OPTIONAL_BLANK: m->str_flags |= STRING_COMPACT_OPTIONAL_BLANK; break; case CHAR_IGNORE_LOWERCASE: m->str_flags |= STRING_IGNORE_LOWERCASE; break; case CHAR_IGNORE_UPPERCASE: m->str_flags |= STRING_IGNORE_UPPERCASE; break; case CHAR_REGEX_OFFSET_START: m->str_flags |= REGEX_OFFSET_START; break; default: if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "string extension `%c' invalid", *l); return -1; } /* allow multiple '/' for readability */ if (l[1] == '/' && !isspace ((ut8)l[2])) l++; } if (string_modifier_check(ms, m) == -1) return -1; } else { if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "invalid string op: %c", *t); return -1; } } /* * We used to set mask to all 1's here, instead let's just not do * anything if mask = 0 (unless you have a better idea) */ EATAB; switch (*l) { case '>': case '<': /* Old-style anding: "0 byte &0x80 dynamically linked" */ case '&': case '^': case '=': m->reln = *l; ++l; if (*l == '=') { /* HP compat: ignore &= etc. */ ++l; } break; case '!': m->reln = *l; ++l; break; default: m->reln = '='; /* the default relation */ if (*l == 'x' && ((isascii((ut8)l[1]) && isspace ((ut8)l[1])) || !l[1])) { m->reln = *l; ++l; } break; } /* * Grab the value part, except for an 'x' reln. */ if (m->reln != 'x' && getvalue (ms, m, &l, action)) return -1; /* * TODO finish this macro and start using it! * #define offsetcheck {if (offset > HOWMANY-1) * magwarn("offset too big"); } */ /* * Now get last part - the description */ EATAB; if (l[0] == '\b') { ++l; m->flag |= NOSPACE; } else if ((l[0] == '\\') && (l[1] == 'b')) { ++l; ++l; m->flag |= NOSPACE; } for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof (m->desc); ) continue; if (i == sizeof (m->desc)) { m->desc[sizeof (m->desc) - 1] = '\0'; if (ms->flags & R_MAGIC_CHECK) file_magwarn(ms, "description `%s' truncated", m->desc); } /* * We only do this check while compiling, or if any of the magic * files were not compiled. */ if (ms->flags & R_MAGIC_CHECK) if (check_format (ms, m) == -1) return -1; if (action == FILE_CHECK) file_mdump (m); m->mimetype[0] = '\0'; /* initialise MIME type to none */ if (m->cont_level == 0) ++(*nmentryp); /* make room for next */ return 0; }
static int magic_parse(char *p) { struct magic *m; char *t, *s; int i, j; if (Magiccnt + 1 > Magicmax) errx(1, "magic_parse: magic table full"); m = &Magic[Magiccnt]; m->flag = 0; m->cont_level = 0; while (*p == '>') { p++; /* step over */ m->cont_level++; } if (m->cont_level != 0 && *p == '(') { p++; /* step over */ m->flag |= INDIR; } if (m->cont_level != 0 && *p == '&') { p++; /* step over */ m->flag |= ADD; } /* Get offset, then skip over it. */ m->offset = (int) strtoul(p, &t, 0); if (p == t) errx(1, "magic_parse: offset %s invalid", p); p = t; if (m->flag & INDIR) { m->in.type = LONG; m->in.offset = 0; /* read [.lbs][+-]nnnnn) */ if (*p == '.') { p++; switch (LOWCASE(*p)) { case 'l': m->in.type = LONG; break; case 'h': case 's': m->in.type = SHORT; break; case 'c': case 'b': m->in.type = BYTE; break; default: errx(1, "magic_parse: indirect offset " "type '%c' invalid", *p); break; } p++; } s = p; if (*p == '+' || *p == '-') p++; if (isdigit((u_char) *p)) { m->in.offset = strtoul(p, &t, 0); if (*s == '-') m->in.offset = - m->in.offset; } else t = p; if (*t++ != ')') errx(1, "magic_parse: missing ')' in indirect offset"); p = t; } while (isascii((u_char) *p) && isdigit((u_char) *p)) p++; while (isascii((u_char) *p) && isspace((u_char) *p)) p++; if (*p == 'u') { p++; m->flag |= UNSIGNED; } /* Get type, skip it. */ t = p; for (i = 0; i < 12; i++) { j = strlen(Magictypes[i]); if (strncmp(p, Magictypes[i], j) == 0) { m->type = i + 1; p += j; break; } } if (p == t) errx(1, "magic_parse: type %s invalid", p); /* New-style and'ing: "0 byte&0x80 =0x80 dynamically linked" */ if (*p == '&') { p++; m->mask = signextend(m, strtoul(p, &p, 0)); eatsize(&p); } else m->mask = ~0L; while (isascii((u_char) *p) && isspace((u_char) *p)) p++; switch(*p) { case '>': case '<': /* Old-style and'ing: "0 byte &0x80 dynamically linked" */ case '&': case '^': case '=': m->reln = *p; p++; break; case '!': if (m->type != STRING) { m->reln = *p; p++; break; } /* FALLTHRU */ default: if (*p == 'x' && isascii((u_char) p[1]) && isspace((u_char) p[1])) { m->reln = *p; p++; goto parse_get_desc; /* Bill The Cat */ } m->reln = '='; break; } while (isascii((u_char) *p) && isspace((u_char) *p)) p++; if (getvalue(m, &p)) return (0); parse_get_desc: /* Now get last part - the description. */ while (isascii((u_char) *p) && isspace((u_char) *p)) p++; strlcpy(m->desc, p, sizeof(m->desc)); if (Opt_debug) { mdump(m); } Magiccnt++; return (1); }