ZipLoader

Small class to load data from zip archive. This class is using zlib and Minizip external libraries.

ZipLoader.h

#ifndef ZIP_LOADER_H
#define ZIP_LOADER_H
 
/*--------------------------------------------------------------------------*/
 
#include <SFML/System/NonCopyable.hpp>
#include <string>
 
/*--------------------------------------------------------------------------*/
// Loads files from zip - or in directory if it exists
// 
namespace Zip
	{
	// Storage class for file loaded from zip
	class File : public sf::NonCopyable
		{
	public:
		// Creates empty file
		File();
		// Construct file from filename, loads file
		File(const std::string &FileName);
		// Destructor
		~File();
 
		// Load file
		void Load(const std::string &FileName);
 
		// Close file, free allocated memory
		void Close(void);
 
		// Return pointer to data
		operator const char *() const
			{ return myData; }
 
		// Return size
		unsigned int Size(void) const
			{ return mySize; }
 
	private:
		// File data pointer and size
		char *myData;
		unsigned int mySize;
		};	
	};
 
/*--------------------------------------------------------------------------*/
 
#endif // ZIP_LOADER_H

ZipLoader.h

#include "ZipLoader.h"
#include <SFML/System.hpp>
#include <iostream>
#include <unzip.h>
 
/*--------------------------------------------------------------------------*/
// Class statics 
 
namespace Zip
	{
	// Define data file
	const char *DataFile="Data.zip";
 
	// Define load mutex
	sf::Mutex LoadMutex;
 
	// Declare loading functions
	const std::string AbsolutePath(const std::string &Name);
	char *LoadNormalFile(const std::string &Filename, unsigned int &Size);
	char *LoadZipFile(const std::string &Filename, unsigned int &Size);
	char *Load(const std::string &Filename, unsigned int &Size);
	}
 
/*--------------------------------------------------------------------------*/
// Parses path to absolute value
//
const std::string Zip::AbsolutePath(const std::string &Name)
	{
	// All \:s need to be changed to /
	std::string Filename(Name);
	std::string::size_type Pos=0;
	while ((Pos=Filename.find('\\',Pos)) != std::string::npos)
		Filename[Pos]='/';
 
	// Check if directory has "..", and remove it
	while ((Pos=Filename.find("/..")) != std::string::npos)
		{
		// Modify path to get absolute path
		std::string::size_type Start=Filename.rfind('/',Pos-1);
		if (Start!=std::string::npos)
			// Remove previous path and ..
			Filename=Filename.substr(0,Start)+Filename.substr(Pos+3);
		}
 
	// Return generated filename
	return Filename;
	}
 
/*--------------------------------------------------------------------------*/
// Loads normal file
//
char *Zip::LoadNormalFile(const std::string &Filename, unsigned int &Size)
	{
	// Try to open the file
	FILE *fp=fopen(Filename.c_str(),"rb");
	if (fp==NULL)
		return NULL;
 
	// Resolve file size
	fseek(fp,0,SEEK_END);
	Size=ftell(fp);
	fseek(fp,0,SEEK_SET);
 
	// Allocate memory and read file
	char *Buffer=new char[Size+1];
	fread(Buffer,1,Size,fp);
	Buffer[Size]=0;		// Add terminating zero
	fclose(fp);
 
	// Return data
	return Buffer;
	}
 
/*--------------------------------------------------------------------------*/
// Loads file from zip
//
char *Zip::LoadZipFile(const std::string &Filename, unsigned int &Size)
	{
	// Open zip file
	unzFile ZipHandle=unzOpen(DataFile);
	if (ZipHandle==NULL)
		return NULL;	// Can't open zip archive
 
	// Create absolute path
	std::string Path=AbsolutePath(Filename);
 
	// Find file
	int Ok=unzLocateFile(ZipHandle,Path.c_str(),false);
	if (Ok!=UNZ_OK)
		return NULL;	// File not found
 
	// Try to open it
	Ok=unzOpenCurrentFile(ZipHandle);
	if (Ok!=UNZ_OK)
		return NULL;	// Can't open requested file from zip
 
	// Resolve file size
	unz_file_info FileInfo;
	unzGetCurrentFileInfo(ZipHandle, &FileInfo, NULL,0, NULL,0, NULL,0);
	Size=FileInfo.uncompressed_size;
 
	// Allocate memory and read the file
	char *Buffer=new char[Size+1];
	unzReadCurrentFile(ZipHandle,Buffer,Size);
	Buffer[Size]=0;
 
	// Close file handles
	unzCloseCurrentFile(ZipHandle);
	unzClose(ZipHandle);
 
	// Return data
	return Buffer;
	}
 
/*--------------------------------------------------------------------------*/
// Reads file to memory
//
char *Zip::Load(const std::string &Filename, unsigned int &Size)
	{
	// Grab mutex
	sf::Lock Lock(LoadMutex);
 
	// Try to load normal file
	char *Data=LoadNormalFile(Filename,Size);
 
	// If that failed, load file from zip
	if (!Data)
		Data=LoadZipFile(Filename,Size);
 
	// If even that failed, then we can't load the file
	if (!Data)
		{
		// You could for example throw an error here, now just returning NULL
		std::cout << "Can't open file: " << Filename << std::endl;
		return NULL;
		}
 
	// Return loaded file
	return Data;
	}
 
/*--------------------------------------------------------------------------*/
// Storage class for file data
/*--------------------------------------------------------------------------*/
 
/*--------------------------------------------------------------------------*/
// Constructors
//
 
// Creates empty file
Zip::File::File() :
		myData(NULL),
		mySize(0)
	{
	// Nothing here
	}
 
// Construct from filename and load requested
Zip::File::File(const std::string &Filename) :
		myData(NULL),
		mySize(0)
	{
	// Load file
	Load(Filename);
	}
 
/*--------------------------------------------------------------------------*/
// Destructor
//
Zip::File::~File()
	{
	// Just close the file
	Close();
	}
 
/*--------------------------------------------------------------------------*/
// Load file
//
void Zip::File::Load(const std::string &Filename)
	{
	// Close old file
	Close();
 
	// Load file
	myData=Zip::Load(Filename,mySize);
	}
 
/*--------------------------------------------------------------------------*/
// Close file, free allocated memory
//
void Zip::File::Close(void)
	{
	// Free old memory
	delete[] myData;
	mySize=0;
	}

Usage

Usage for images and fonts is straightforward:

void LoadData(void)
	{
	// Load image file
	Zip::File File("Data/test.png");
	if (!Image.LoadFromMemory(File,File.Size()))
		return EXIT_FAILURE;
 
	// Load font
	File.Load("Data/test.ttf");
	if (!Font.LoadFromMemory(File,File.Size()))
		return EXIT_FAILURE;
	}

Loading music has a catch. When you load music from memory, it means that music will be played from that memory. Therefore that data must exist while music is playing, so Zip::File containing that data must not go out of scope.

void main(void)
	{
	// Load music
	sf::Music Music;
	Zip::File File("Data/test.ogg");
	if (!Music.OpenFromMemory(File,File.Size()))
		return EXIT_FAILURE;	
 
	// Play the music
	Music.Play();
 
	... do something ...
 
	// Stop music before Zip::File will get deleted
	Music.Stop();
	}

You can load full sources with example compiled for Windows from here: ZipLoader

 
en/sources/ziploader.txt · Last modified: 2009/07/27 08:22 by Jaenis
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki