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 + -
显示快捷键?