Ticket #8912: kyra_resource_parent_cache_v7.diff

File kyra_resource_parent_cache_v7.diff, 10.4 KB (added by tramboi, 12 years ago)
  • resource.h

     
    4343
    4444struct ResFileEntry {
    4545        Common::String parent;
     46        mutable ResFileEntry *parentEntry;      // Cache to avoid lookup by string in the map
     47                                                                                // No smart invalidation is needed because the map is cleared globally
     48                                                                                // or expanded but no element is ever removed
    4649        uint32 size;
    4750
    4851        bool preload;
     
    128131        bool loadFileToBuf(const char *file, void *buf, uint32 maxSize);
    129132protected:
    130133        void checkFile(const Common::String &file);
    131         bool isAccessable(const Common::String &file);
     134        bool isAccessible(const Common::String &file);
     135        bool isAccessible(const ResFileEntry *fileEntry);
    132136
    133137        void detectFileTypes();
     138        void detectFileType(const Common::String &filename, ResFileEntry *fileEntry);
    134139
    135140        void initializeLoaders();
    136141        const ResArchiveLoader *getLoader(ResFileEntry::kType type) const;
     
    140145        LoaderList _loaders;
    141146        ResFileMap _map;
    142147
     148        ResFileEntry *getParentEntry(const ResFileEntry *entry) const;
     149        ResFileEntry *getParentEntry(const Common::String &filename) const;
     150
    143151        typedef Common::List<Common::SharedPtr<CompArchiveLoader> > CompLoaderList;
    144152        typedef CompLoaderList::iterator CompLoaderIterator;
    145153        typedef CompLoaderList::const_iterator CCompLoaderIterator;
  • resource.cpp

     
    150150}
    151151
    152152bool Resource::loadPakFile(const Common::String &filename) {
    153         if (!isAccessable(filename))
     153        if (!isAccessible(filename))
    154154                return false;
    155155
    156156        ResFileMap::iterator iter = _map.find(filename);
     
    201201                                                // If the old parent is not protected we mark it as not preload anymore,
    202202                                                // since now no longer all of its embedded files are in the filemap.
    203203                                                oldParent->_value.preload = false;
    204                                                 _map[i->filename] = i->entry;
     204                                                iter->_value = i->entry;
    205205                                        }
    206206                                } else {
    207207                                        // Old parent not found? That's strange... But we just overwrite the old
    208208                                        // entry.
    209                                         _map[i->filename] = i->entry;
     209                                        iter->_value = i->entry;
    210210                                }
    211211                        } else {
    212212                                // The old parent has the same filenames as the new archive, we are sure and overwrite the
    213213                                // old file entry, could be afterall that the preload flag of the new archive was
    214214                                // just unflagged.
    215                                 _map[i->filename] = i->entry;
     215                                iter->_value = i->entry;
    216216                        }
    217217                }
    218218                // 'else' case would mean here overwriting an existing file entry in the map without parent.
     
    244244                filename.toUppercase();
    245245
    246246                if (filename.hasSuffix(".PAK")) {
    247                         if (!isAccessable(filename) && _vm->gameFlags().isDemo) {
     247                        if (!isAccessible(filename) && _vm->gameFlags().isDemo) {
    248248                                // the demo version supplied with Kyra3 does not
    249249                                // contain all pak files listed in filedata.fdt
    250250                                // so we don't do anything here if they are non
     
    289289}
    290290
    291291bool Resource::isInPakList(const Common::String &filename) {
    292         if (!isAccessable(filename))
     292        if (!isAccessible(filename))
    293293                return false;
    294294        ResFileMap::iterator iter = _map.find(filename);
    295295        if (iter == _map.end())
     
    320320bool Resource::exists(const char *file, bool errorOutOnFail) {
    321321        if (Common::File::exists(file))
    322322                return true;
    323         else if (isAccessable(file))
     323        else if (isAccessible(file))
    324324                return true;
    325325        else if (errorOutOnFail)
    326326                error("File '%s' can't be found", file);
     
    335335                if (f.open(file))
    336336                        return f.size();
    337337        } else {
    338                 if (!isAccessable(file))
     338                if (!isAccessible(file))
    339339                        return 0;
    340340
    341341                ResFileMap::const_iterator iter = _map.find(file);
     
    362362        if ((compEntry = _compFiles.find(file)) != _compFiles.end())
    363363                return new Common::MemoryReadStream(compEntry->_value.data, compEntry->_value.size, false);             
    364364
    365         if (!isAccessable(file))
     365        if (!isAccessible(file))
    366366                return 0;
    367367
    368368        ResFileMap::const_iterator iter = _map.find(file);
     
    381381                Common::SeekableReadStream *parent = getFileStream(iter->_value.parent);
    382382                assert(parent);
    383383
    384                 ResFileMap::const_iterator parentIter = _map.find(iter->_value.parent);
    385                 const ResArchiveLoader *loader = getLoader(parentIter->_value.type);
     384                ResFileEntry* parentEntry = getParentEntry(&iter->_value);
     385                const ResArchiveLoader *loader = getLoader(parentEntry->type);
    386386                assert(loader);
    387387
    388388                return loader->loadFileFromArchive(file, parent, iter->_value);
     
    391391        return 0;
    392392}
    393393
    394 bool Resource::isAccessable(const Common::String &file) {
     394bool Resource::isAccessible(const Common::String &file) {
    395395        checkFile(file);
    396396
    397397        ResFileMap::const_iterator iter = _map.find(file);
    398         while (iter != _map.end()) {
    399                 if (!iter->_value.parent.empty()) {
    400                         iter = _map.find(iter->_value.parent);
    401                         if (iter != _map.end()) {
    402                                 // parent can never be a non archive file
    403                                 if (iter->_value.type == ResFileEntry::kRaw)
    404                                         return false;
    405                                 // not mounted parent means not accessable
    406                                 else if (!iter->_value.mounted)
    407                                         return false;
    408                         }
     398        if (iter == _map.end())
     399                return false;
     400       
     401        return isAccessible(&iter->_value);
     402}
     403
     404bool Resource::isAccessible(const ResFileEntry *fileEntry) {
     405        assert(fileEntry);
     406       
     407        const ResFileEntry* currentEntry = fileEntry;
     408        while (not currentEntry->parent.empty()) {
     409                if (currentEntry->parentEntry) {
     410                        currentEntry = currentEntry->parentEntry;
    409411                } else {
    410                         return true;
     412                        ResFileMap::iterator it = _map.find(currentEntry->parent);
     413                        if (it == _map.end())
     414                                return false;
     415                        else
     416                                currentEntry->parentEntry = &it->_value;
    411417                }
     418                // parent can never be a non archive file
     419                if (currentEntry->type == ResFileEntry::kRaw)
     420                        return false;
     421                // not mounted parent means not accessable
     422                else if (!currentEntry->mounted)
     423                        return false;
    412424        }
    413         return false;
     425       
     426        return true;
    414427}
    415428
     429ResFileEntry *Resource::getParentEntry(const ResFileEntry *entry) const {
     430        assert(entry);
     431        if (entry->parent.empty())
     432                return 0;
     433        else if (entry->parentEntry) {
     434                assert(_map.find(entry->parent) != _map.end()); // If some day the hash map implementations changes and moves nodes around,
     435                                                                                                                // this assumption would fail and the whole system would need a refactoring
     436                assert(entry->parentEntry == &_map.find(entry->parent)->_value);
     437                return entry->parentEntry;
     438        } else {
     439                ResFileMap::iterator it = _map.find(entry->parent);
     440                if (it == _map.end())
     441                        return 0; // If it happens often, the structure maybe deserves a flag to avoid rechecking the map
     442                else {
     443                        entry->parentEntry = &it->_value;
     444                        return entry->parentEntry;
     445                }
     446        }
     447}
     448
     449ResFileEntry *Resource::getParentEntry(const Common::String &filename) const {
     450        ResFileMap::iterator it = _map.find(filename);
     451        assert(it != _map.end());
     452        return getParentEntry(&it->_value);
     453}
     454
    416455void Resource::checkFile(const Common::String &file) {
    417456        if (_map.find(file) == _map.end()) {
    418457                CompFileMap::const_iterator iter;
    419458
    420459                if ((iter = _compFiles.find(file)) != _compFiles.end()) {
    421                         ResFileEntry entry;
     460                        ResFileEntry& entry = _map[file];
    422461                        entry.parent = "";
     462                        entry.parentEntry = 0;
    423463                        entry.size = iter->_value.size;
    424464                        entry.mounted = false;
    425465                        entry.preload = false;
    426466                        entry.prot = false;
    427467                        entry.type = ResFileEntry::kAutoDetect;
    428468                        entry.offset = 0;
    429                         _map[file] = entry;
    430 
    431                         detectFileTypes();
     469                       
     470                        detectFileType(file, &entry);
    432471                } else if (Common::File::exists(file)) {
    433472                        Common::File temp;
    434473                        if (temp.open(file)) {
    435                                 ResFileEntry entry;
     474                                ResFileEntry& entry = _map[file];
    436475                                entry.parent = "";
     476                                entry.parentEntry = 0;
    437477                                entry.size = temp.size();
    438478                                entry.mounted = file.compareToIgnoreCase(StaticResource::staticDataFilename()) != 0;
    439479                                entry.preload = false;
    440480                                entry.prot = false;
    441481                                entry.type = ResFileEntry::kAutoDetect;
    442482                                entry.offset = 0;
    443                                 _map[file] = entry;
    444483                                temp.close();
    445484
    446                                 detectFileTypes();
     485                                detectFileType(file, &entry);
    447486                        }
    448487                }
    449488        }
    450489}
    451490
    452 void Resource::detectFileTypes() {
    453         for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i) {
    454                 if (!isAccessable(i->_key))
    455                         continue;
     491void Resource::detectFileType(const Common::String &filename, ResFileEntry *fileEntry) {
     492        assert(fileEntry);
     493       
     494        if (!isAccessible(fileEntry))
     495                return;
    456496
    457                 if (i->_value.type == ResFileEntry::kAutoDetect) {
    458                         Common::SeekableReadStream *stream = 0;
    459                         for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
    460                                 if (!(*l)->checkFilename(i->_key))
    461                                         continue;
    462                                
    463                                 if (!stream)
    464                                         stream = getFileStream(i->_key);
     497        if (fileEntry->type == ResFileEntry::kAutoDetect) {
     498                Common::SeekableReadStream *stream = 0;
     499                for (LoaderIterator l = _loaders.begin(); l != _loaders.end(); ++l) {
     500                        if (!(*l)->checkFilename(filename))
     501                                continue;
     502                       
     503                        if (!stream)
     504                                stream = getFileStream(filename);
    465505
    466                                 if ((*l)->isLoadable(i->_key, *stream)) {
    467                                         i->_value.type = (*l)->getType();
    468                                         i->_value.mounted = false;
    469                                         i->_value.preload = false;
    470                                         break;
    471                                 }
     506                        if ((*l)->isLoadable(filename, *stream)) {
     507                                fileEntry->type = (*l)->getType();
     508                                fileEntry->mounted = false;
     509                                fileEntry->preload = false;
     510                                break;
    472511                        }
    473                         delete stream;
    474                         stream = 0;
     512                }
     513                delete stream;
     514                stream = 0;
    475515
    476                         if (i->_value.type == ResFileEntry::kAutoDetect)
    477                                 i->_value.type = ResFileEntry::kRaw;
    478                 }
     516                if (fileEntry->type == ResFileEntry::kAutoDetect)
     517                        fileEntry->type = ResFileEntry::kRaw;
    479518        }
    480519}
    481520
     521void Resource::detectFileTypes() {
     522        for (ResFileMap::iterator i = _map.begin(); i != _map.end(); ++i)
     523                detectFileType(i->_key, &i->_value);
     524}
     525
    482526void Resource::tryLoadCompFiles() {
    483527        for (CCompLoaderIterator i = _compLoaders.begin(); i != _compLoaders.end(); ++i) {
    484528                if ((*i)->checkForFiles())
     
    620664                        entry.size = endoffset - startoffset;
    621665                        entry.offset = startoffset;
    622666                        entry.parent = filename;
     667                        entry.parentEntry = 0;
    623668                        entry.type = ResFileEntry::kAutoDetect;
    624669                        entry.mounted = false;
    625670                        entry.prot = false;
     
    738783        for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
    739784                ResFileEntry entry;
    740785                entry.parent = filename;
     786                entry.parentEntry = 0;
    741787                entry.type = ResFileEntry::kAutoDetect;
    742788                entry.mounted = false;
    743789                entry.preload = false;
     
    807853        for (uint i = 0; i < entries; ++i) {
    808854                ResFileEntry entry;
    809855                entry.parent = filename;
     856                entry.parentEntry = 0;
    810857                entry.type = ResFileEntry::kAutoDetect;
    811858                entry.mounted = false;
    812859                entry.preload = false;