/*!\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; }
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); }
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); }