/* ScummVM - Scumm Interpreter * Copyright (C) 2004-2005 The ScummVM project * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ * */ #include "common/stdafx.h" #include "common/file.h" #include "kyra/resource.h" #include "kyra/script.h" #include "kyra/wsamovie.h" namespace Kyra { Resource::Resource(KyraEngine* engine) { _engine = engine; // No PAK files in the demo version if (_engine->game() == KYRA1DEMO) return; // prefetches all PAK Files // ugly a hardcoded list // TODO: use the FS Backend to get all .PAK Files and load them // or any other thing to get all files static const char* kyra1Filelist[] = { "A_E.PAK", "DAT.PAK", "F_L.PAK", "MAP_5.PAK", "MSC.PAK", "M_S.PAK", "S_Z.PAK", "WSA1.PAK", "WSA2.PAK", "WSA3.PAK", "WSA4.PAK", "WSA5.PAK", "WSA6.PAK", 0 }; static const char* kyra1CDFilelist[] = { "ADL.PAK", "BRINS.PAK", "CLIFF.PAK", "ENTER.PAK", "FORESTA.PAK", "GEM.PAK", "INTRO1.PAK", "LEPHOLE.PAK", "OAKS.PAK", "SPELL.PAK", "WILLOW.PAK", "ALCHEMY.PAK", "BROKEN.PAK", "COL.PAK", "EXTHEAL.PAK", "FORESTB.PAK", "GEMCUT.PAK", "INTRO2.PAK", "LIBRARY.PAK", "PLATEAU.PAK", "SPRING.PAK", "WISE.PAK", "ALGAE.PAK", "BURN.PAK", "DARMS.PAK", "EXTPOT.PAK", "FORESTC.PAK", "GENCAVB.PAK", "INTRO3.PAK", "MISC.PAK", "PLTCAVE.PAK", "SQUARE.PAK", "XEDGE.PAK", "ALTAR.PAK", "CASTLE.PAK", "DEAD.PAK", "EXTSPEL.PAK", "FOUNTN.PAK", "GENHALL.PAK", "INTRO4.PAK", "MIX.PAK", "POTION.PAK", "STARTUP.PAK", "XEDGEB.PAK", "ARCH.PAK", "CATACOM.PAK", "DNSTAIR.PAK", "FALLS.PAK", "FOYER.PAK", "GEN_CAV.PAK", "KITCHEN.PAK", "MOONCAV.PAK", "RUBY.PAK", "STUMP.PAK", "XEDGEC.PAK", "BALCONY.PAK", "CAVE.PAK", "DRAGON.PAK", "FESTSTH.PAK", "FSOUTH.PAK", "GLADE.PAK", "KYRAGEM.PAK", "NCLIFF.PAK", "SICKWIL.PAK", "TEMPLE.PAK", "XMI.PAK", "BELROOM.PAK", "CAVEB.PAK", "EDGE.PAK", "FGOWEST.PAK", "FSOUTHB.PAK", "GRAVE.PAK", "LAGOON.PAK", "NCLIFFB.PAK", "SND.PAK", "TRUNK.PAK", "ZROCK.PAK", "BONKBG.PAK", "CGATE.PAK", "EDGEB.PAK", "FINALE.PAK", "FWSTSTH.PAK", "GRTHALL.PAK", "LANDING.PAK", "NWCLIFB.PAK", "SONG.PAK", "UPSTAIR.PAK", "BRIDGE.PAK", "CHASM.PAK", "EMCAV.PAK", "FNORTH.PAK", "GATECV.PAK", "HEALER.PAK", "LAVA.PAK", "NWCLIFF.PAK", "SORROW.PAK", "WELL.PAK", 0 }; const char** usedFilelist = 0; if (_engine->game() == KYRA1) usedFilelist = kyra1Filelist; else if (_engine->game() == KYRA1CD) usedFilelist = kyra1CDFilelist; else error("no filelist found for this game"); for (uint32 tmp = 0; usedFilelist[tmp]; ++tmp) { // prefetch file PAKFile* file = new PAKFile(usedFilelist[tmp]); assert(file); PakFileEntry newPak; newPak._file = file; strncpy(newPak._filename, usedFilelist[tmp], 32); if (file->isOpen() && file->isValid()) _pakfiles.push_back(newPak); else { delete file; debug("couldn't load file '%s' correctly", usedFilelist[tmp]); } } } Resource::~Resource() { Common::List::iterator start = _pakfiles.begin(); for (;start != _pakfiles.end(); ++start) { delete start->_file; start->_file = 0; } } bool Resource::loadPakFile(const char *filename) { if (isInPakList(filename)) return true; PAKFile* file = new PAKFile(filename); if (!file) { error("Couldn't load file: '%s'", filename); } PakFileEntry newPak; newPak._file = file; strncpy(newPak._filename, filename, 32); _pakfiles.push_back(newPak); return true; } void Resource::unloadPakFile(const char *filename) { Common::List::iterator start = _pakfiles.begin(); for (;start != _pakfiles.end(); ++start) { if (scumm_stricmp(start->_filename, filename) == 0) { delete start->_file; _pakfiles.erase(start); break; } } return; } bool Resource::isInPakList(const char *filename) { Common::List::iterator start = _pakfiles.begin(); for (;start != _pakfiles.end(); ++start) { if (scumm_stricmp(start->_filename, filename) == 0) return true; } return false; } uint8* Resource::fileData(const char* file, uint32* size) { uint8* buffer = 0; Common::File file_; // test to open it in the main dir if (file_.open(file)) { *size = file_.size(); buffer = new uint8[*size]; assert(buffer); file_.read(buffer, *size); file_.close(); } else { // opens the file in a PAK File Common::List::iterator start = _pakfiles.begin(); for (;start != _pakfiles.end(); ++start) { *size = start->_file->getFileSize(file); if (!(*size)) continue; buffer = new uint8[*size]; assert(buffer); // TODO: maybe remove this again, this is only // because I had problems when using gcc 4.0.1 const uint8 *from = start->_file->getFile(file); assert(from); // creates a copy of the file memcpy(buffer, from, *size); break; } } if (!buffer || !(*size)) { return 0; } return buffer; } VMContext* Resource::loadScript(const char* file) { VMContext* context = new VMContext(_engine); context->loadScript(file); return context; } /////////////////////////////////////////// // Pak file manager #define PAKFile_Iterate Common::List::iterator start=_files.begin();start != _files.end(); ++start PAKFile::PAKFile(const Common::String& file) { Common::File pakfile; _buffer = 0; _open = false; if (!pakfile.open(file.c_str())) { printf("pakfile couldn't open %s\n", file.c_str()); return; } uint32 filesize = pakfile.size(); _buffer = new uint8[filesize]; assert(_buffer); pakfile.read(_buffer, filesize); pakfile.close(); // works with the file uint32 pos = 0, startoffset = 0, endoffset = 0; startoffset = READ_LE_UINT32(_buffer + pos); pos += 4; while (pos < filesize) { PakChunk* chunk = new PakChunk; assert(chunk); // saves the name chunk->_name = reinterpret_cast(_buffer + pos); pos += strlen(chunk->_name) + 1; if (!(*chunk->_name)) break; endoffset = READ_LE_UINT32(_buffer + pos); pos += 4; if (endoffset == 0) { endoffset = filesize; } chunk->_data = _buffer + startoffset; chunk->_size = endoffset - startoffset; _files.push_back(chunk); if (endoffset == filesize) break; startoffset = endoffset; } _open = true; } PAKFile::~PAKFile() { delete [] _buffer; _buffer = 0; _open = false; for (PAKFile_Iterate) { delete *start; *start = 0; } } const uint8* PAKFile::getFile(const char* file) { for (PAKFile_Iterate) { if (!scumm_stricmp((*start)->_name, file)) return (*start)->_data; } return 0; } uint32 PAKFile::getFileSize(const char* file) { for (PAKFile_Iterate) { if (!scumm_stricmp((*start)->_name, file)) return (*start)->_size; } return 0; } } // end of namespace Kyra