Beispiel #1
0
/*!\brief Prüfen, ob es sich um ein PFP-File handelt
 *
 * \desc
 * Diese Funktion prüft, ob es sich bei der geöffneten Datei \p ff um eine Datei
 * im \ref PFPFileVersion3 PFP-Format Version 3 handelt. Ist dies der Fall, wird deren
 * ID und Version eingelesen.
 *
 * @param ff Referenz auf eine geöffnete Datei
 * @return Gibt \c true zurück, wenn es sich um eine Datei im PFP-Format handelt. Deren
 * ID kann anschließend mit PFPFile::getID ausgelesen werden, Version mit PFPFile::getVersion bzw.
 * PFPFile::getMainVersion und PFPFile::getSubVersion. Handelt es sich nicht um eine Datei
 * im PFP-Format, gibt die Funktion \c false zurück. Es wird keine Exception geworfen.
 */
bool PFPFile::ident(FileObject &ff)
{
	try {
		const char *p;
		p=ff.map(0,24);
		if (strncmp(p,"PFP-File",8)!=0) return false;
		if (Peek8(p+8)!=3) return false;
		id.set(p+10,4);
		mainversion=Peek8(p+15);
		subversion=Peek8(p+14);
		comp=(Compression::Algorithm)Peek8(p+16);
		return true;
	} catch (...) {
		return false;
	}
	return false;
}
/**
 *	Reads a null-or-return-terminated string from the stream
 *	
 *	If the buffer is too small to hold the entire string, it is truncated and
 *	properly terminated.
 *	
 *	@param buf the output buffer
 *	@param bufLength the size of the output buffer
 *	@return the number of characters written to the buffer
 */
UInt32 IDataStream::ReadString(char * buf, UInt32 bufLength, char altTerminator, char altTerminator2)
{
	char	* traverse = buf;
	bool	breakOnReturns = false;

	if((altTerminator == '\n') || (altTerminator2 == '\n'))
		breakOnReturns = true;

	ASSERT_STR(bufLength > 0, "IDataStream::ReadString: zero-sized buffer");

	if(bufLength == 1)
	{
		buf[0] = 0;
		return 0;
	}

	bufLength--;

	for(UInt32 i = 0; i < bufLength; i++)
	{
		if(HitEOF()) break;

		UInt8	data = Read8();

		if(breakOnReturns)
		{
			if(data == 0x0D)
			{
				if(Peek8() == 0x0A)
					Skip(1);

				break;
			}
		}

		if(!data || (data == altTerminator) || (data == altTerminator2))
		{
			break;
		}

		*traverse++ = data;
	}

	*traverse++ = 0;

	return traverse - buf - 1;
}
Beispiel #3
0
void Sprite::loadTexture(PFPChunk *chunk)
/*!\brief Laden eines Texture-Chunks
 *
 * \desc
 * Diese Funktion wird intern verwendet, um einen SURF-Chunk mit einer
 * Textur aus der Sprite-Datei zu laden.
 *
 * \param[in] chunk Pointer auf den zu ladenden SURF-Chunk
 * \param[in] flags Flags, mit dem das Texture-Surfaces erstellt werden soll.
 * Dies ist eine Kombination der Werte innerhalb der Enumeration ppl6::grafix::Surface::Flags
 * \returns Konnte die Textur erfolgreich geladen werden,
 * liefert die Funktion true (1) zurück, andernfalls false (0).
 */
{
	Compression Comp;
	Comp.usePrefix(Compression::Prefix_V2);
	char *buffer=(char*)chunk->data();
	// Textur anlegen
	SpriteTexture tex;
	// Zunächst lesen wir dem Header
	tex.id=Peek16(buffer+0);
	int rgbformat=Peek8(buffer+2);
	switch (rgbformat) {
		case 9: tex.rgbformat=RGBFormat::A8R8G8B8;
				break;
		default:
			throw UnsupportedColorFormatException();
	}
	tex.bitdepth=Peek8(buffer+3);
	tex.width=Peek16(buffer+4);
	tex.height=Peek16(buffer+6);
	// Nutzdaten dekomprimieren
	ByteArray uncompressed;
	Comp.uncompress(uncompressed,buffer+8,chunk->size()-8);
	buffer=(char*)uncompressed.ptr();
	// Nun erstellen wir ein neues Surface
	tex.surface.create(tex.width,tex.height,tex.rgbformat);
	for (int y=0;y<tex.height;y++) {
		for (int x=0;x<tex.width;x++) {
			if (tex.rgbformat==RGBFormat::A8R8G8B8) {
				tex.surface.putPixel(x,y,Color(Peek8(buffer+2),Peek8(buffer+1),Peek8(buffer),Peek8(buffer+3)));
				buffer+=4;
			}
		}
	}
	TextureList.add(tex.id,tex);
}
Beispiel #4
0
void PFPFile::load(FileObject &ff)
/*!\brief PFP-File laden
 *
 * Mit dieser Funktion wird ein PFP-File in die Klasse geladen. Dabei wird zuerst der Header geladen
 * und überprüft, ob es sich um ein gültiges PFP-File handelt. Dann wird die virtuelle Funktion
 * PFPFile::LoadRequest mit ID, Haupt- und Unterversion als Parameter aufgerufen. Liefert diese
 * nicht true (1) zurück, wird der Ladevorgang abgebrochen. Andernfalls wird fortgeführt
 * und geprüft, ob der
 * Datenbereich komprimiert ist und gegebenenfalls dekomprimiert. Erst danach werden die
 * einzelnen Chunks eingelesen. Kommt es dabei zu Fehlern durch ungültige Chunks, werden diese
 * ignoriert und die Funktion gibt den Fehlercode 434 zurück.
 *
 * \param ff Pointer auf eine CFile-Klasse, mit der die einzulesende Datei geöffnet wurde.
 * \returns Konnte die Datei fehlerfrei eingelesen werden, gibt die Funktion true (1) zurück,
 * im Fehlerfall false (0). Ein entsprechender Fehlercode wird gesetzt.
 *
 * \remarks
 * Vor dem Laden der Datei wird die Funktion PFPFile::Clear aufgerufen, so dass eventuell vorher
 * vorhandene Daten verloren gehen.
 *
 * \since Version 6.1.0
 */
{
	const char *p;
	try {
		p=ff.map(0,24);
	} catch (OverflowException &) {
		throw InvalidFormatException();
	}
	if (strncmp(p,"PFP-File",8)!=0) throw InvalidFormatException();
	if (Peek8(p+8)!=3) throw InvalidFormatException();
	size_t z,fsize;
	// Wir haben ein gültiges PFP-File, aber dürfen wir es auch laden?
	char tmpid[5];
	tmpid[4]=0;
	strncpy(tmpid,p+10,4);
	int t1,t2;
	t1=Peek8(p+15);
	t2=Peek8(p+14);
	if (!loadRequest(tmpid,t1,t2)) {
		throw AccessDeniedByInstanceException();
	}
	clear();
	id.set(p+10,4);
	mainversion=Peek8(p+15);
	subversion=Peek8(p+14);
	comp=(Compression::Algorithm)Peek8(p+16);
	size_t hsize=Peek8(p+9);
	char *u=NULL;
	if (comp) {
		p=(char*)ff.map(hsize,8);
		if (!p) throw ReadException();
		size_t sizeunk=Peek32(p);
		size_t sizecomp=Peek32(p+4);
		p=ff.map(hsize+8,sizecomp);
		if (!p) throw ReadException();
		u=(char*)malloc(sizeunk+1);
		if (!u) throw OutOfMemoryException();
		size_t dstlen=sizeunk;
		Compression c;
		try {
			c.init(comp);
			c.uncompress(u,&dstlen,p,sizecomp);
		} catch (...) {
			free(u);
			clear();
			throw;
		}
		if (dstlen!=sizeunk) {
			free(u);
			clear();
			throw DecompressionFailedException();
		}
		u[dstlen]=0;
		p=u;
		fsize=dstlen;
	} else {
		p=ff.map();
		p+=hsize;
		fsize=ff.size()-hsize;
	}
	// Wir haben nun den ersten Chunk ab Pointer p
	z=0;
	String Chunkname;
	try {
		size_t size=0;
		while ((z+=size)<fsize) {
			size=Peek32(p+z+4);
			if (strncmp(p+z,"ENDF",4)==0) break;
			if (!size) break;
			// Falls z+size über das Ende der Datei geht, stimmt mit diesem Chunk was nicht
			if (z+size>fsize) break;
			PFPChunk *chunk=new PFPChunk;
			if (!chunk) throw OutOfMemoryException();
			Chunkname.set(p+z,4);
			chunk->setName(Chunkname);
			chunk->setData(p+z+8,size-8);
			addChunk(chunk);
		}
	} catch (...) {
		if (u) free(u);
		clear();
		throw;
	}
	if (u) free(u);
}