apprentice.c
来自「sleuthit-2.09 一个磁盘的工具集」· C语言 代码 · 共 1,854 行 · 第 1/3 页
C
1,854 行
protected uint64_tfile_signextend(struct magic_set *ms, struct magic *m, uint64_t v){ if (!(m->flag & UNSIGNED)) { switch(m->type) { /* * Do not remove the casts below. They are * vital. When later compared with the data, * the sign extension must have happened. */ case FILE_BYTE: v = (char) v; break; case FILE_SHORT: case FILE_BESHORT: case FILE_LESHORT: v = (short) v; break; case FILE_DATE: case FILE_BEDATE: case FILE_LEDATE: case FILE_MEDATE: case FILE_LDATE: case FILE_BELDATE: case FILE_LELDATE: case FILE_MELDATE: case FILE_LONG: case FILE_BELONG: case FILE_LELONG: case FILE_MELONG: v = (int32_t) v; break; case FILE_QUAD: case FILE_BEQUAD: case FILE_LEQUAD: case FILE_QDATE: case FILE_QLDATE: case FILE_BEQDATE: case FILE_BEQLDATE: case FILE_LEQDATE: case FILE_LEQLDATE: v = (int64_t) v; break; case FILE_STRING: case FILE_PSTRING: case FILE_BESTRING16: case FILE_LESTRING16: case FILE_REGEX: case FILE_SEARCH: case FILE_DEFAULT: break; default: if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "cannot happen: m->type=%d\n", m->type); return ~0U; } } return v;}private intstring_modifier_check(struct magic_set *ms, struct magic const *m){ if ((ms->flags & MAGIC_CHECK) == 0) return 0; switch (m->type) { case FILE_BESTRING16: case FILE_LESTRING16: if (m->str_flags != 0) { file_magwarn(ms, "no modifiers allowed for 16-bit strings\n"); return -1; } break; case FILE_STRING: case FILE_PSTRING: if ((m->str_flags & REGEX_OFFSET_START) != 0) { file_magwarn(ms, "'/%c' only allowed on regex and search\n", CHAR_REGEX_OFFSET_START); return -1; } break; case FILE_SEARCH: break; case FILE_REGEX: if ((m->str_flags & STRING_COMPACT_BLANK) != 0) { file_magwarn(ms, "'/%c' not allowed on regex\n", CHAR_COMPACT_BLANK); return -1; } if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) { file_magwarn(ms, "'/%c' not allowed on regex\n", CHAR_COMPACT_OPTIONAL_BLANK); return -1; } break; default: file_magwarn(ms, "coding error: m->type=%d\n", m->type); return -1; } return 0;}private intget_op(char c){ switch (c) { case '&': return FILE_OPAND; case '|': return FILE_OPOR; case '^': return FILE_OPXOR; case '+': return FILE_OPADD; case '-': return FILE_OPMINUS; case '*': return FILE_OPMULTIPLY; case '/': return FILE_OPDIVIDE; case '%': return FILE_OPMODULO; default: return -1; }}#ifdef ENABLE_CONDITIONALSprivate intget_cond(const char *l, const char **t){ static struct cond_tbl_s { const char *name; const size_t len; const int cond; } cond_tbl[] = { { "if", 2, COND_IF }, { "elif", 4, COND_ELIF }, { "else", 4, COND_ELSE }, { NULL, 0, COND_NONE }, }; struct cond_tbl_s *p; for (p = cond_tbl; p->name; p++) { if (strncmp(l, p->name, p->len) == 0 && isspace((unsigned char)l[p->len])) { if (t) *t = l + p->len; break; } } return p->cond;}private intcheck_cond(struct magic_set *ms, int cond, uint32_t cont_level){ int last_cond; last_cond = ms->c.li[cont_level].last_cond; switch (cond) { case COND_IF: if (last_cond != COND_NONE && last_cond != COND_ELIF) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "syntax error: `if'"); return -1; } last_cond = COND_IF; break; case COND_ELIF: if (last_cond != COND_IF && last_cond != COND_ELIF) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "syntax error: `elif'"); return -1; } last_cond = COND_ELIF; break; case COND_ELSE: if (last_cond != COND_IF && last_cond != COND_ELIF) { if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "syntax error: `else'"); return -1; } last_cond = COND_NONE; break; case COND_NONE: last_cond = COND_NONE; break; } ms->c.li[cont_level].last_cond = last_cond; return 0;}#endif /* ENABLE_CONDITIONALS *//* * parse one line from magic file, put into magic[index++] if valid */private intparse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, const char *line, size_t lineno, int action){#ifdef ENABLE_CONDITIONALS static uint32_t last_cont_level = 0;#endif size_t i; struct magic_entry *me; struct magic *m; const char *l = line; char *t; int op; uint32_t cont_level; cont_level = 0; while (*l == '>') { ++l; /* step over */ cont_level++; }#ifdef ENABLE_CONDITIONALS if (cont_level == 0 || cont_level > last_cont_level) if (file_check_mem(ms, cont_level) == -1) return -1; last_cont_level = cont_level;#endif#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 magic *nm; size_t cnt = me->max_count + ALLOC_CHUNK; if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) { file_oomem(ms, sizeof(*nm) * cnt); return -1; } me->mp = m = 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 magic_entry *mp; maxmagic += ALLOC_INCR; if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) == NULL) { 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 == NULL) { if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) { 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 & MAGIC_CHECK) file_magwarn(ms, "relative offset at level 0"); /* get offset, then skip over it */ m->offset = (uint32_t)strtoul(l, &t, 0); if (l == t) if (ms->flags & 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; default: if (ms->flags & 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((unsigned char)*l) || *l == '-') { m->in_offset = (int32_t)strtol(l, &t, 0); if (l == t) if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "in_offset `%s' invalid", l); l = t; } if (*l++ != ')' || ((m->in_op & FILE_OPINDIRECT) && *l++ != ')')) if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "missing ')' in indirect offset"); } EATAB;#ifdef ENABLE_CONDITIONALS m->cond = get_cond(l, &l); if (check_cond(ms, m->cond, cont_level) == -1) return -1; EATAB;#endif if (*l == 'u') { ++l; m->flag |= UNSIGNED; } m->type = get_type(l, &l); if (m->type == FILE_INVALID) { if (ms->flags & 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 (!IS_STRING(m->type)) m->mask_op |= FILE_OPINVERSE; else if (ms->flags & MAGIC_CHECK) file_magwarn(ms, "'~' invalid for string types"); ++l; } m->str_count = 0; m->str_flags = 0; m->num_mask = 0; if ((op = get_op(*l)) != -1) { if (!IS_STRING(m->type)) { uint64_t val; ++l; m->mask_op |= op; val = (uint64_t)strtoull(l, &t, 0); l = t; m->num_mask = file_signextend(ms, m, val); eatsize(&l); } else if (op == FILE_OPDIVIDE) { int have_count = 0; while (!isspace((unsigned char)*++l)) { switch (*l) { /* for portability avoid "case '0' ... '9':" */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (have_count && ms->flags & MAGIC_CHECK) file_magwarn(ms, "multiple counts"); have_count = 1; m->str_count = strtoul(l, &t, 0); 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 & MAGIC_CHECK) file_magwarn(ms, "string extension `%c' invalid", *l); return -1; } /* allow multiple '/' for readability */ if (l[1] == '/' && !isspace((unsigned char)l[2])) l++; } if (string_modifier_check(ms, m) == -1) return -1; } else { if (ms->flags & 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((unsigned char)l[1]) && isspace((unsigned char)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->nospflag = 1; } else if ((l[0] == '\\') && (l[1] == 'b')) { ++l; ++l; m->nospflag = 1; } else m->nospflag = 0; 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 & 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 & MAGIC_CHECK) { if (check_format(ms, m) == -1) return -1; }#ifndef COMPILE_ONLY if (action == FILE_CHECK) { file_mdump(m); }#endif if (m->cont_level == 0) ++(*nmentryp); /* make room for next */ return 0;}private intcheck_format_type(const char *ptr, int type){ int quad = 0; if (*ptr == '\0') { /* Missing format string; bad */ return -1; } switch (type) { case FILE_FMT_QUAD: quad = 1; /*FALLTHROUGH*/ case FILE_FMT_NUM: if (*ptr == '-') ptr++; if (*ptr == '.') ptr++; while (isdigit((unsigned char)*ptr)) ptr++; if (*ptr == '.') ptr++; while (isdigit((unsigned char)*ptr)) ptr++; if (quad) { if (*ptr++ != 'l') return -1; if (*ptr++ != 'l') return -1; } switch (*ptr++) { case 'l': switch (*ptr++) { case 'i': case 'd': case 'u': case 'x': case 'X': return 0; default: return -1; } case 'h': switch (*ptr++) { case 'h': switch (*ptr++) { case 'i': case 'd': case 'u': case 'x': case 'X': return 0; default: return -1; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?