/** * lädt eine GER/ENG-File in ein ArchivInfo. * * @param[in] file Dateiname der GER/ENG-File * @param[out] items ArchivInfo-Struktur, welche gefüllt wird * @param[in] conversion Soll ggf. OEM-Charset in ANSI umgewandelt werden? * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @bug Keine Erkennung ob Plain-Text oder "Irgendwas". * * @author FloSoft */ int libsiedler2::loader::LoadTXT(const char* file, ArchivInfo* items, bool conversion) { FILE* txt; short header; long length; if(file == NULL || items == NULL) return 1; // Datei zum lesen öffnen txt = fopen(file, "rb"); // hat das geklappt? if(txt == NULL) return 2; // Länge bestimmen fseek(txt, 0, SEEK_END); length = ftell(txt); fseek(txt, 0, SEEK_SET); // Header einlesen if(libendian::be_read_s(&header, txt) != 0) return 3; // ist es eine TXT-File? (Header 0xE7FD) if( header != (short)0xE7FD ) { // den Header zurückspringen fseek(txt, -2, SEEK_CUR); // Plain-Text items->alloc(1); ArchivItem_Text* item = (ArchivItem_Text*)(*allocator)(BOBTYPE_TEXT, 0, NULL); item->load(txt, conversion); // Item erzeugen items->set(0, item); } else { // "archiviert" unsigned short count, unknown; unsigned int size; if(libendian::le_read_us(&count, txt) != 0) return 4; if(libendian::le_read_us(&unknown, txt) != 0) return 5; if(libendian::le_read_ui(&size, txt) != 0) return 6; if(size == 0) size = length; else size += 10; // Anzahl alloziieren items->alloc(count); int* starts = new int[count]; memset(starts, 0, sizeof(int)*count); // Starts einlesen for(unsigned short x = 0; x < count; ++x) { int s; if(libendian::le_read_i(&s, txt) != 0) return 7; if(s != 0) starts[x] = s + 10; } // Daten einlesen, zwecks Längenbestimmung unsigned int pos = ftell(txt); unsigned int rest = size - pos; char* buffer = new char[rest + 1]; if(libendian::le_read_c(buffer, rest, txt) != (int)rest) return 8; for(unsigned short x = 0; x < count; ++x) { int i = starts[x]; if(i != 0) { // An Start springen fseek(txt, i, SEEK_SET); // einlesen ArchivItem_Text* item = (ArchivItem_Text*)(*allocator)(BOBTYPE_TEXT, 0, NULL); item->load(txt, conversion, (unsigned int)strlen(&buffer[i - pos])); items->set(x, item); } else items->set(x, (ArchivItem_Text*)(*allocator)(BOBTYPE_TEXT, 0, NULL)); } delete[] buffer; delete[] starts; } // alles ok return 0; }
/** * 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; }
/** * lädt eine GER/ENG-File in ein ArchivInfo. * * @param[in] file Dateiname der GER/ENG-File * @param[out] items ArchivInfo-Struktur, welche gefüllt wird * @param[in] conversion Soll ggf. OEM-Charset in ANSI umgewandelt werden? * * @return Null bei Erfolg, ein Wert ungleich Null bei Fehler * * @bug Keine Erkennung ob Plain-Text oder "Irgendwas". */ int libsiedler2::loader::LoadTXT(const std::string& file, ArchivInfo& items, bool conversion) { short header; if(file.empty()) return 1; // Datei zum lesen öffnen boost::iostreams::mapped_file_source mmapFile; try{ mmapFile.open(bfs::path(file)); }catch(std::exception& e){ std::cerr << "Could not open '" << file << "': " << e.what() << std::endl; return 2; } typedef boost::iostreams::stream<boost::iostreams::mapped_file_source> MMStream; MMStream mmapStream(mmapFile); libendian::EndianIStream<false, MMStream& > fs(mmapStream); // hat das geklappt? if(!fs) return 2; size_t length = getIStreamSize(fs.getStream()); assert(length < std::numeric_limits<unsigned>::max()); // Header einlesen fs >> header; items.clear(); // ist es eine TXT-File? (Header 0xE7FD) if( header != (short)0xFDE7 ) { // den Header zurückspringen fs.setPositionRel(-2); ArchivItem_Text* item = (ArchivItem_Text*)getAllocator().create(BOBTYPE_TEXT); item->load(fs.getStream(), conversion); items.push(item); } else { // "archiviert" unsigned short count, unknown; unsigned int size; fs >> count; fs >> unknown; fs >> size; if(size == 0) size = static_cast<unsigned>(length); else size += 10; std::vector<unsigned> starts(count); // Starts einlesen for(unsigned short x = 0; x < count; ++x) { uint32_t s; fs >> s; if(s != 0) starts[x] = s + 10; } // Daten einlesen, zwecks Längenbestimmung size_t pos = fs.getPosition(); size_t rest = size - pos; std::vector<char> buffer(rest + 1); buffer.resize(rest); fs >> buffer; buffer.push_back(0); for(unsigned short x = 0; x < count; ++x) { unsigned i = starts[x]; if(i != 0) { // An Start springen fs.setPosition(i); // einlesen ArchivItem_Text* item = (ArchivItem_Text*)getAllocator().create(BOBTYPE_TEXT); assert(i >= pos); item->load(fs.getStream(), conversion, (unsigned int)strlen(&buffer[i - pos]) + 1); items.push(item); } else items.push(NULL); } } // alles ok return 0; }