Talk:SDL:Tutorials:Displaying a Bitmap from a zip file using SDL RWops and zlib

From GDWiki

Jump to: navigation, search

[edit] zlib & SDL_RWops

This entry using SDL_RWops and zlib a bit limited in that you can only get SDL_RWops from a file. I'm trying to figure out how to get a SDL_RWops from a SDL_RWops of a zipfile, but I'm having problems with zlib's function calls.

I can copy a zip file into memory, call SDL_RWFromMem() on it to create a SDL_RWops, and then parse though the data to find the chunk of data that represents the compressed info. I get an error 'Z_DATA_ERROR' when I call zlib's uncompress() function.

compresseddata = new Uint8[compressedsize];
uncompresseddata = new Uint8[uncompressedsize];
blocks = SDL_RWread(rw, compresseddata, compressedsize, 1);
if (blocks != 1) {
	printf("Error reading data.\n");
	exit(1);
}
 
unsigned long size = uncompressedsize;
ret = uncompress( uncompresseddata, &size, compresseddata, compressedsize );
printf("zlib::uncompress returns %d\n", ret);

Once I figure out how to get zlib to decompress the data, all that needs to be done is call SDL_RWFromMem() on it. Any help with using zlib would be appreciated.

-rppowell


Since zlib has functions that read from a zip file, you can write out the SDL_RWops into a temp file, re-open it with zlib functions and get the data from in that.

// This function returns a SDL_RWops of a file within a SDL_RWops of a zipfile
SDL_RWops * SDL_RWops_From_SDL_RWops_zipfile( SDL_RWops *rw_zip, char *filename ) {
	char *tmpfilename;
	FILE *tmpfile;
	int size, i;
	Uint8	uint8;
 
	unzFile		zip;
	unz_file_info	info;
	Uint8		*buffer;
	SDL_RWops	*rw_out;
	int		result;
 
	// create and open unique tmpfile, keeping track of the name
	tmpfilename = tmpnam( NULL );
	tmpfile = fopen(tmpfilename, "wb+");
 
	// write the SDL_RWops into the tmpfile
	SDL_RWseek(rw_zip, 0, SEEK_SET);
	size = SDL_RWtell(rw_zip);
	if (size != 0) {
		printf("SDL_RWseek( SEEK_SET ) not at start of file\n");
		return NULL;
	}
	SDL_RWseek(rw_zip, 0, SEEK_END);
	size = SDL_RWtell(rw_zip);
 
	SDL_RWseek(rw_zip, 0, SEEK_SET);
	for(i=0; i<size; i++) {
		result = SDL_RWread(rw_zip, &uint8, 1, 1);
		result = fputc(uint8, tmpfile);
	}
	fclose(tmpfile);
 
	// now we can use zlib/unzip functions to access 'tmpfilename' like a file
	zip = unzOpen( tmpfilename );
	if ( zip == NULL ) {
		printf("Error opening tmpzipfile with unzOpen('%s')\n", tmpfilename);
		remove(tmpfilename);
		return NULL;
	}
 
	// search for the file within the zipfile
	result = unzLocateFile( zip, filename, 0 );
	if ( result != UNZ_OK ) {
		printf("unzLocateFile('%s') != UNZ_OK(%d)\n", filename, result);
		unzClose(zip);
		remove(tmpfilename);
		return NULL;
	}
 
	result = unzGetCurrentFileInfo( zip, &info, NULL, 0, NULL, 0, NULL, 0 );
	if ( result != UNZ_OK ) {
		printf("unzGetCurrentFileInfo() != UNZ_OK (%d)\n", result);
		unzClose(zip);
		remove(tmpfilename);
		return NULL;
	}
 
	result = unzOpenCurrentFile( zip );
	if ( result != UNZ_OK ) {
		printf("unzOpenCurrentFile() != UNZ_OK (%d)\n", result);
		unzClose(zip);
		remove(tmpfilename);
		return NULL;
	}
 
	buffer = new Uint8[info.uncompressed_size];
	result = unzReadCurrentFile( zip, buffer, info.uncompressed_size );
	if ( result != info.uncompressed_size ) {
		printf("unzReadCurrentFile() Error (%d != %d)\n", result, info.uncompressed_size);
		delete buffer;
		remove(tmpfilename);
		return NULL;
	}
	unzClose(zip);
	remove(tmpfilename);
 
	rw_out = SDL_RWFromMem(buffer, info.uncompressed_size);
	if(!rw_out) {
		printf("Error with SDL_RWFromMem: %s\n", SDL_GetError() );
		delete buffer;
		return NULL;
	}
 
	// Note: we do not handle deleting the allocate memory for the new SDL_RWops,
	// SDL_freeRW() should do that for us.
	return rw_out;
}
 
 
SDL_RWops *zip;
SDL_RWops *bmp;
 
// open our zipfile into a SDL_RWops
zip = SDL_RWFromFile("data.zip", "rb");
if(!zip) {
	printf("Error opening archive.zip with SDL_RWFromFile: %s\n", SDL_GetError() );
	exit(1);
}
 
bmp = SDL_RWops_From_SDL_RWops_zipfile(zip, "bitmap.bmp");

In theory, we can also access zipfiles from within zipfiles.