Esempio n. 1
0
int bmp_isfile(const uint8_t *data, size_t input_len, size_t *lengthptr)
{
	if (input_len < (BMP_HEADER_SIZE + DIB_HEADER_SIZE) || !IS_BMP_MAGIC(data))
		return 0;

	const struct bmp_header *header = (const struct bmp_header *)data;

	size_t   filesize      = le32toh(header->filesize);
	uint16_t reserved1     = le16toh(header->reserved1);
	uint16_t reserved2     = le16toh(header->reserved2);
	size_t   dataoffset    = le32toh(header->dataoffset);
	size_t   headersize    = le32toh(header->headersize);
	int32_t  width         = le32toh(header->width);
	int32_t  height        = le32toh(header->height);
	uint16_t planes        = le16toh(header->planes);
	uint16_t bpp           = le16toh(header->bpp);
	uint32_t compression   = le32toh(header->compression);
	size_t   datasize      = le32toh(header->datasize);
	size_t   palettecolors = le32toh(header->palettecolors);
	size_t   colortblsize  = 4 * palettecolors;

	// integer overflow?
	if (SIZE_MAX / 4 < palettecolors)
		return 0;

	// sanity of all sizes and offsets
	if (filesize < (BMP_HEADER_SIZE + DIB_HEADER_SIZE) || dataoffset >= filesize || datasize >= filesize ||
		headersize >= filesize || headersize < DIB_HEADER_SIZE || colortblsize >= filesize ||
		dataoffset < (BMP_HEADER_SIZE + headersize + colortblsize) ||
		filesize - datasize < dataoffset)
		return 0;

	// legal range of values?
	if (width <= 0 || height == 0 || planes != 1 || bpp == 0 ||
		reserved1 != 0 || reserved2 != 0 || compression > 6)
		return 0;

	if (filesize > input_len)
		return 0;

	if (lengthptr)
		*lengthptr = filesize;
	
	return 1;
}
Esempio n. 2
0
int do_extract(const uint8_t *filedata, size_t filesize, const struct extract_options *options, size_t *numfilesptr, size_t *sumsizeptr)
{
	const uint8_t *ptr = NULL, *end = NULL;
	enum fileformat format = NONE;

	size_t sumsize = 0;
	size_t length = 0;
	int success = 1;
	int formats = options->formats;
	char *outfilename = NULL;

	size_t numfiles = 0;
	const char *filename = basename(options->filepath);
	// max. ext length is 16 characters
	size_t namelen = strlen(options->outdir) + strlen(filename) + 37;

	struct mpg123_info mpg123;
	struct ogg_info ogg;
	struct file_info info = {0, 0};
	size_t count = 0; // e.g. for tracks count in midi
	const uint8_t *audio_start = NULL;
	size_t input_len = 0;

	outfilename = malloc(namelen);
	if (outfilename == NULL)
	{
		perror(options->filepath);
		goto error;
	}

	if (!options->quiet)
	{
		double slice_size = 0;
		const char *slice_unit = format_size(filesize, &slice_size);
		printf("Extracting 0x%08"PRIx64" ... 0x%08"PRIx64" (%g %s) from %s\n",
			options->offset,
			options->offset + filesize,
			slice_size, slice_unit,
			options->filepath);
	}

#define WRITE_FILE(data, length, ext) \
	if (write_file((data), length, options, filename, (size_t)((data) - filedata), (ext), outfilename, namelen)) \
	{ \
		++ numfiles; \
		sumsize += length; \
	}
	
	ptr = filedata;
	end = filedata + filesize;
	for (input_len = filesize; input_len >= 4; input_len = (size_t)(end - ptr))
	{
		uint32_t magic = MAGIC(ptr);
		
		if (formats & OGG && magic == OGG_MAGIC && ogg_ispage(ptr, input_len, &ogg))
		{
			uint32_t pageno = ogg.pageno;
			audio_start = ptr;

			for (;;)
			{
				ptr += ogg.length;
				
				if (!ogg_ispage(ptr, (size_t)(end - ptr), &ogg) || ogg.pageno <= pageno)
					break;

				pageno = ogg.pageno;
			}

			WRITE_FILE(audio_start, ptr - audio_start, "ogg");
			continue;
		}

		if (formats & RIFF && magic == RIFF_MAGIC && riff_isfile(ptr, input_len, &info))
		{
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}
		
		if (formats & AIFF && magic == FORM_MAGIC && aiff_isfile(ptr, input_len, &info))
		{
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}
		
		if (formats & MIDI && magic == MIDI_MAGIC && midi_isheader(ptr, input_len, &length, &count))
		{
			audio_start = ptr;
			do {
				ptr += length;
			} while (count-- > 0 && midi_istrack(ptr, (size_t)(end - ptr), &length));

			if (count != 0 && !(options->quiet))
			{
				fprintf(stderr, "warning: midi file misses %"PRIzu" tracks\n", count);
			}

			WRITE_FILE(audio_start, ptr - audio_start, "mid");
			continue;
		}
		
		format = NONE;
		if (formats & ID3v2 && IS_ID3v2_MAGIC(ptr) && id3v2_istag(ptr, input_len, 0, &length))
		{
			format = ID3v2;
		}

		if (formats & MPG123 && IS_MPG123_MAGIC(ptr))
		{
			format = MPG123;
			length = 0;
		}

		if (format & (ID3v2 | MPG123) && mpg123_isframe(ptr + length, input_len - length, &mpg123))
		{
			uint8_t version = mpg123.version;
			uint8_t layer   = mpg123.layer;

			audio_start = ptr;
			ptr += length;

			do {
				ptr += mpg123.frame_size;
			} while (mpg123_isframe(ptr, (size_t)(end - ptr), &mpg123)
			      && mpg123.version == version
			      && mpg123.layer   == layer);
					
			if (id3v1_istag(ptr, (size_t)(end - ptr), &length))
			{
				ptr += length;
			}

			if (formats & ID3v2 && id3v2_istag(ptr, (size_t)(end - ptr), 1, &length))
			{
				ptr += length;
			}
					
			WRITE_FILE(audio_start, ptr - audio_start,
				layer == 1 ? "mp1" :
				layer == 2 ? "mp2" :
				layer == 3 ? "mp3" :
				             "mpg");
			continue;
		}
		
		if (formats & IT && magic == IT_MAGIC && it_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "it");
			ptr += length;
			continue;
		}

		if (formats & XM && magic == XM_MAGIC && xm_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "xm");
			ptr += length;
			continue;
		}

		if (formats & ASF && magic == ASF_MAGIC && asf_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "asf");
			ptr += length;
			continue;
		}

		if (formats & AU && magic == AU_MAGIC && au_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "au");
			ptr += length;
			continue;
		}

		if (formats & PNG && magic == PNG_MAGIC && png_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "png");
			ptr += length;
			continue;
		}

		if (formats & GIF && magic == GIF_MAGIC && gif_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "gif");
			ptr += length;
			continue;
		}

		if (formats & (MPEG1 | MPEGPS | MPEGVS) && IS_MPEG_MAGIC(magic) && mpeg_isfile(ptr, input_len, formats, &length))
		{
			WRITE_FILE(ptr, length, "mpg");
			ptr += length;
			continue;
		}

		if (formats & MPEGTS && IS_MPEG_TS_MAGIC(ptr) && mpeg_isfile(ptr, input_len, formats, &length))
		{
			WRITE_FILE(ptr, length, "mpg");
			ptr += length;
			continue;
		}

		if (formats & JPEG && IS_JPG_MAGIC(magic) && jpg_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "jpg");
			ptr += length;
			continue;
		}

		if (formats & BINK && IS_BINK_MAGIC(magic) && bink_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "bik");
			ptr += length;
			continue;
		}

		if (formats & BMP && IS_BMP_MAGIC(ptr) && bmp_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "bmp");
			ptr += length;
			continue;
		}

		if (formats & SMK && IS_SMK_MAGIC(magic) && smk_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "smk");
			ptr += length;
			continue;
		}

		if (formats & MP4 && input_len > MP4_HEADER_SIZE &&
			MAGIC(ptr + MP4_MAGIC_OFFSET) == MP4_MAGIC &&
			mp4_isfile(ptr, input_len, &info))
		{
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		if (formats & S3M && input_len > S3M_MAGIC_OFFSET + 4 &&
			MAGIC(ptr + S3M_MAGIC_OFFSET) == S3M_MAGIC &&
			s3m_isfile(ptr, input_len, &length))
		{
			WRITE_FILE(ptr, length, "s3m");
			ptr += length;
			continue;
		}

		if (formats & MOD && input_len > MOD_MAGIC_OFFSET + 4)
		{
			const uint8_t *modmagic = ptr + MOD_MAGIC_OFFSET;
			if (IS_MOD_MAGIC(modmagic) && mod_isfile(ptr, input_len, &length))
			{
				WRITE_FILE(ptr, length, "mod");
				ptr += length;
				continue;
			}
		}

		if (formats & UTF_32LE && utf32le_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		if (formats & UTF_32BE && utf32be_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		if (formats & UTF_16LE && utf16le_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		if (formats & UTF_16BE && utf16be_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		if (formats & UTF_8 && utf8_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}
		else if (formats & ASCII && ascii_isfile(ptr, input_len, &info)) {
			WRITE_FILE(ptr, info.length, info.ext);
			ptr += info.length;
			continue;
		}

		++ ptr;
	}

	goto cleanup;

error:
	success = 0;

cleanup:
	if (outfilename)
		free(outfilename);

	if (numfilesptr)
		*numfilesptr = numfiles;
	
	if (sumsizeptr)
		*sumsizeptr = sumsize;

	return success;
}