/** * lädt eine ACT-File in ein ArchivInfo. * * @param[in] file Dateiname der ACT-File * @param[out] items ArchivInfo-Struktur, welche gefüllt wird * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @author FloSoft * @author OLiver */ int libsiedler2::loader::LoadACT(const std::string& file, ArchivInfo& items) { long size; if(file.empty()) return 1; // Datei zum lesen öffnen boost::scoped_ptr<FILE> act(fopen(file.c_str(), "rb")); // hat das geklappt? if(!act) return 2; fseek(act.get(), 0, SEEK_END); size = ftell(act.get()); fseek(act.get(), 0, SEEK_SET); // sind es 256*3 Bytes, also somit 8bit-RGB? if(size != 256*3) return 3; ArchivItem_Palette* palette = (ArchivItem_Palette*)getAllocator().create(BOBTYPE_PALETTE); if(palette->load(act.get(), false) != 0){ delete palette; return 4; } // einlesen items.clear(); items.push(palette); // Alles OK return 0; }
bool ArchivItem_BitmapBase::checkPalette(const ArchivItem_Palette& palette) const { if(format_ == FORMAT_PALETTED) return true; for(unsigned y = 0; y < height_; y++) { for(unsigned x = 0; x < width_; x++) { ColorARGB clr = getARGBPixel(x, y); uint8_t dummyIdx; if(clr.getAlpha() != 0 && !palette.lookup(clr, dummyIdx)) return false; } } return true; }
/** * lädt eine spezifizierten Bobtype aus einer Datei in ein ArchivItem. * * @param[in] bobtype Typ des Items * @param[in] file Filehandle auf die auszulesende Datei * @param[in] palette Grundpalette * @param[out] item ArchivItem-Struktur, welche gefüllt wird * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler */ int libsiedler2::loader::LoadType(BOBTYPES bobtype, std::istream& file, const ArchivItem_Palette* palette, ArchivItem*& item) { if(!file) return 1; try{ switch(bobtype) { case BOBTYPE_SOUND: // WAVs, MIDIs { libendian::LittleEndianIStreamRef fs(file); unsigned int length; fs >> length; baseArchivItem_Sound* nitem = baseArchivItem_Sound::findSubType(file); if(!nitem || nitem->load(file, length) != 0){ delete nitem; return 5; } item = nitem; } break; case BOBTYPE_BITMAP_RLE: // RLE komprimiertes Bitmap { baseArchivItem_Bitmap_RLE* nitem = dynamic_cast<baseArchivItem_Bitmap_RLE*>(getAllocator().create(BOBTYPE_BITMAP_RLE)); if(nitem->load(file, palette) != 0){ delete nitem; return 6; } item = nitem; } break; case BOBTYPE_FONT: // Font { ArchivItem_Font* nitem = dynamic_cast<ArchivItem_Font*>(getAllocator().create(BOBTYPE_FONT)); if(nitem->load(file, palette) != 0){ delete nitem; return 7; } item = nitem; } break; case BOBTYPE_BITMAP_PLAYER: // Bitmap mit spezifischer Spielerfarbe { ArchivItem_Bitmap_Player* nitem = dynamic_cast<ArchivItem_Bitmap_Player*>(getAllocator().create(BOBTYPE_BITMAP_PLAYER)); if(nitem->load(file, palette) != 0){ delete nitem; return 8; } item = nitem; } break; case BOBTYPE_PALETTE: // Palette { ArchivItem_Palette* nitem = dynamic_cast<ArchivItem_Palette*>(getAllocator().create(BOBTYPE_PALETTE)); if(nitem->load(file) != 0){ delete nitem; return 9; } item = nitem; } break; case BOBTYPE_BOB: // Bobfile { ArchivItem_Bob* nitem = dynamic_cast<ArchivItem_Bob*>(getAllocator().create(BOBTYPE_BOB)); if(nitem->load(file, palette) != 0){ delete nitem; return 10; } item = nitem; } break; case BOBTYPE_BITMAP_SHADOW: // Schatten { baseArchivItem_Bitmap_Shadow* nitem = dynamic_cast<baseArchivItem_Bitmap_Shadow*>(getAllocator().create(BOBTYPE_BITMAP_SHADOW)); if(nitem->load(file, palette) != 0){ delete nitem; return 11; } item = nitem; } break; case BOBTYPE_MAP: // Mapfile { ArchivItem_Map* nitem = dynamic_cast<ArchivItem_Map*>(getAllocator().create(BOBTYPE_MAP)); if(nitem->load(file, false) != 0){ delete nitem; return 12; } item = nitem; } break; case BOBTYPE_TEXT: // Textfile { ArchivItem_Text* nitem = dynamic_cast<ArchivItem_Text*>(getAllocator().create(BOBTYPE_TEXT)); if(nitem->load(file) != 0){ delete nitem; return 13; } item = nitem; } break; case BOBTYPE_BITMAP_RAW: // unkomprimiertes Bitmap { baseArchivItem_Bitmap_Raw* nitem = dynamic_cast<baseArchivItem_Bitmap_Raw*>(getAllocator().create(BOBTYPE_BITMAP_RAW)); if(nitem->load(file, palette) != 0){ delete nitem; return 14; } item = nitem; } break; case BOBTYPE_NONE: item = NULL; break; default: item = NULL; return 42; } if(item != NULL) item->setBobType(bobtype); }catch(std::runtime_error&){ // Mostly error on reading (e.g. unexpected end of file) return 999; } return 0; }
/** * schreibt ein ArchivInfo in eine BBM-File. * * @param[in] file Dateiname der BBM-File * @param[in] items ArchivInfo-Struktur, von welcher gelesen wird * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @author FloSoft */ int libsiedler2::loader::WriteBBM(const char* file, const ArchivInfo* items) { FILE* bbm; char header[5] = "FORM", pbm[5] = "PBM ", cmap[5] = "CMAP"; unsigned long count = 0; unsigned int length = 0; if(file == NULL || items == NULL) return 1; // Anzahl Paletten in ArchivInfo suchen for(unsigned long i = 0; i < items->getCount(); ++i) { if(!items->get(i)) continue; if(items->get(i)->getBobType() == BOBTYPE_PALETTE) ++count; } // Datei zum schreiben öffnen bbm = fopen(file, "wb"); // hat das geklappt? if(bbm == NULL) return 2; // Header schreiben if(libendian::le_write_c(header, 4, bbm) != 4) return 3; // Länge schreiben length = 4 + count * (256 * 3 + 8); if(libendian::le_write_ui(length, bbm) != 0) return 4; // Typ schreiben if(libendian::le_write_c(pbm, 4, bbm) != 4) return 5; for(unsigned long i = 0; i < items->getCount(); ++i) { ArchivItem_Palette* palette = (ArchivItem_Palette*)items->get(i); if(palette->getBobType() == BOBTYPE_PALETTE) { // Chunk schreiben if(libendian::be_write_c(cmap, 4, bbm) != 4) return 6; // Länge schreiben length = 256 * 3; if(libendian::be_write_ui(length, bbm) != 0) return 7; // Farbpalette zuweisen unsigned char colors[256][3]; for(unsigned int k = 0; k < 256; ++k) palette->get(k, &colors[k][0], &colors[k][1], &colors[k][2]); // Farbpalette schreiben if(libendian::le_write_uc(colors[0], 256 * 3, bbm) != 256 * 3) return 8; } } // Datei schliessen fclose(bbm); // alles ok return 0; }
/** * lädt eine BBM-File in ein ArchivInfo. * * @param[in] file Dateiname der BBM-File * @param[out] items ArchivInfo-Struktur, welche gefüllt wird * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @author FloSoft * @author OLiver */ int libsiedler2::loader::LoadBBM(const std::string& file, ArchivInfo& items) { char header[4], pbm[4]; unsigned int chunk; unsigned int i = 0; if(file.empty()) return 1; // Datei zum lesen öffnen boost::scoped_ptr<FILE> bbm(fopen(file.c_str(), "rb")); // hat das geklappt? if(!bbm) return 2; long size = getFileLength(bbm.get()); // Header einlesen if(libendian::le_read_c(header, 4, bbm.get()) != 4) return 3; // ist es eine BBM-File? (Header "FORM") if(strncmp(header, "FORM", 4) != 0) return 4; // Länge einlesen unsigned length; if(libendian::le_read_ui(&length, bbm.get()) != 0) return 5; // Typ einlesen if(libendian::le_read_c(pbm, 4, bbm.get()) != 4) return 6; // ist es eine BBM-File? (Typ "PBM ") if(strncmp(pbm, "PBM ", 4) != 0) return 7; // Chunks einlesen while(!feof(bbm.get()) && ftell(bbm.get()) < size) { // Chunk-Typ einlesen if(libendian::be_read_ui(&chunk, bbm.get()) != 0) return 8; switch(chunk) { case 0x434D4150: // "CMAP" { // Länge einlesen if(libendian::be_read_ui(&length, bbm.get()) != 0) return 9; // Bei ungerader Zahl aufrunden if(length & 1) ++length; // Ist Länge wirklich so groß wie Farbtabelle? if(length != 256 * 3) return 10; // Daten von Item auswerten ArchivItem_Palette* palette = (ArchivItem_Palette*)getAllocator().create(BOBTYPE_PALETTE); items.push(palette); size_t namePos = file.find_last_of('/'); if(namePos != std::string::npos) { std::stringstream rName; rName << file.substr(namePos+1) << "(" << i << ")"; palette->setName(rName.str()); } // Farbpalette lesen Color colors[256]; if(libendian::le_read_uc(&colors[0].r, sizeof(colors), bbm.get()) != sizeof(colors)) return 10; // Farbpalette zuweisen for(unsigned int k = 0; k < 256; ++k) palette->set(k, colors[k]); ++i; } break; default: { // Länge einlesen if(libendian::be_read_ui(&length, bbm.get()) != 0) return 12; // Bei ungerader Zahl aufrunden if(length & 1) ++length; if(length > 0) { boost::scoped_array<unsigned char> buffer(new unsigned char[length]); // überspringen if(libendian::le_read_uc(buffer.get(), length, bbm.get()) != (int)length) return 13; } } break; } } if(items.size() == 0) return 14; // alles ok return 0; }
/** * lädt eine LBM-File in ein ArchivInfo. * * @param[in] file Dateiname der LBM-File * @param[out] items ArchivInfo-Struktur, welche gefüllt wird * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @author FloSoft * @author OLiver */ int libsiedler2::loader::LoadLBM(const char* file, ArchivInfo* items) { FILE* lbm; char header[4], pbm[4]; unsigned int chunk; unsigned int length; long size; if(file == NULL || items == NULL) return 1; // Datei zum lesen öffnen lbm = fopen(file, "rb"); // hat das geklappt? if(lbm == NULL) return 2; fseek(lbm, 0, SEEK_END); size = ftell(lbm); fseek(lbm, 0, SEEK_SET); // Header einlesen if(libendian::le_read_c(header, 4, lbm) != 4) return 3; // ist es eine LBM-File? (Header "FORM") if(strncmp(header, "FORM", 4) != 0) return 4; // Länge einlesen if(libendian::le_read_ui(&length, lbm) != 0) return 5; // Typ einlesen if(libendian::le_read_c(pbm, 4, lbm) != 4) return 6; // ist es eine LBM-File? (Typ "PBM ") if(strncmp(pbm, "PBM ", 4) != 0) return 7; baseArchivItem_Bitmap* bitmap = dynamic_cast<baseArchivItem_Bitmap*>((*allocator)(BOBTYPE_BITMAP_RAW, 0, NULL)); bitmap->setFormat(FORMAT_PALETTED); ArchivItem_Palette* palette = NULL; unsigned short compression; unsigned short width, height; unsigned short depth; // lbm has normally 2 items, palette (1) and image (0), // i'll change position of those items to be compatible with LoadBMP items->alloc(2); // Chunks einlesen while(!feof(lbm) && ftell(lbm) < size) { // Chunk-Typ einlesen if(libendian::be_read_ui(&chunk, lbm) != 0) return 8; switch(chunk) { case 0x424D4844: // "BHMD" { // Länge einlesen if(libendian::be_read_ui(&length, lbm) != 0) return 9; // Bei ungerader Zahl aufrunden if(length & 1) ++length; if(libendian::be_read_us(&width, lbm) != 0) return 10; if(libendian::be_read_us(&height, lbm) != 0) return 11; bitmap->setWidth(width); bitmap->setHeight(height); // Unbekannte Daten ( 4 Byte ) berspringen fseek(lbm, 4, SEEK_CUR); // Farbtiefe einlesen if(libendian::le_read_us(&depth, lbm) != 0) return 12; // Nur 256 Farben und nicht mehr! if(depth != 8) return 13; // Kompressionflag lesen if(libendian::le_read_us(&compression, lbm) != 0) return 14; // Keine bekannte Kompressionsart? if(compression > 1) return 15; length -= 12; // Rest überspringen fseek(lbm, length, SEEK_CUR); } break; case 0x434D4150: // "CMAP" { // Länge einlesen if(libendian::be_read_ui(&length, lbm) != 0) return 16; // Bei ungerader Zahl aufrunden if(length & 1) ++length; // Ist Länge wirklich so groß wie Farbtabelle? if(length != 256 * 3) return 17; // Daten von Item auswerten palette = (ArchivItem_Palette*)(*allocator)(BOBTYPE_PALETTE, 0, NULL); items->set(1, palette); // Farbpalette lesen unsigned char colors[256][3]; if(libendian::le_read_uc(colors[0], 256 * 3, lbm) != 256 * 3) return 18; // Farbpalette zuweisen for(unsigned int k = 0; k < 256; ++k) palette->set(k, colors[k][0], colors[k][1], colors[k][2]); } break; case 0x424F4459: // "BODY" { // Länge einlesen if(libendian::be_read_ui(&length, lbm) != 0) return 19; // Bei ungerader Zahl aufrunden if(length & 1) ++length; // haben wir eine Palette erhalten? if(palette == NULL) return 20; bitmap->setPalette(palette); bitmap->tex_alloc(); switch(compression) { case 0: // unkomprimiert { /*assert(false);*/ } break; case 1: // komprimiert (RLE?) { // Welcher Pixel ist dran? unsigned short x = 0, y = 0; unsigned char ctype; unsigned char color; // Solange einlesen, bis Block zuende bzw. Datei zuende ist while(length >= 0 && !feof(lbm) && ftell(lbm) < size) { // Typ lesen if(libendian::le_read_uc(&ctype, 1, lbm) != 1) return 21; --length; if(length == 0) continue; if(ctype < 128) // unkomprimierte Pixel { unsigned short count = ctype + 1; for(unsigned short i = 0; i < count; ++i) { // Farbe auslesen if(libendian::le_read_uc(&color, 1, lbm) != 1) return 22; --length; bitmap->tex_setPixel(x++, y, color, palette); if(x >= width) { ++y; x = 0; } } } else // komprimierte Pixel { unsigned short count = 0xFF - ctype + 2; // Farbe auslesen if(libendian::le_read_uc(&color, 1, lbm) != 1) return 23; --length; for(unsigned short i = 0; i < count; ++i) { bitmap->tex_setPixel(x++, y, color, palette); if(x >= width) { ++y; x = 0; } } } } } break; } items->set(0, bitmap); } break; default: { // Länge einlesen if(libendian::be_read_ui(&length, lbm) != 0) return 24; // Bei ungerader Zahl aufrunden if(length & 1) ++length; // Rest überspringen fseek(lbm, length, SEEK_CUR); } break; } } if(items->getCount() == 0) return 25; // Datei schliessen fclose(lbm); return 0; }