Skip to content

Commit

Permalink
libdoomsday|Resources: Added LumpCatalog: package-aware WAD lump indexer
Browse files Browse the repository at this point in the history
Currently implements a simple WAD lump directory latest-lump-applies
logic, operating in any specified package order.
  • Loading branch information
skyjake committed Mar 29, 2016
1 parent 6c3eb08 commit d0c270a
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 4 deletions.
1 change: 1 addition & 0 deletions doomsday/apps/libdoomsday/include/doomsday/LumpCatalog
@@ -0,0 +1 @@
#include "resource/lumpcatalog.h"
59 changes: 59 additions & 0 deletions doomsday/apps/libdoomsday/include/doomsday/resource/lumpcatalog.h
@@ -0,0 +1,59 @@
/** @file lumpcatalog.h Catalog of lumps from multiple bundles.
*
* @authors Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDOOMSDAY_LUMPCATALOG_H
#define LIBDOOMSDAY_LUMPCATALOG_H

#include "../libdoomsday.h"
#include <de/String>
#include <de/Block>

namespace res {

/**
* Catalog of lumps from multiple bundles.
*
* This is a utility for locating and reading lumps from a set of data bundles.
* It does not cache data: caching should either occur in the File objects or
* a LumpBank that is backed by a LumpCatalog.
*/
class LIBDOOMSDAY_PUBLIC LumpCatalog
{
public:
LumpCatalog();

/**
* Sets the list of packages where data lumps are to be read from. Only data bundle
* packages of Wad and Lump types are used.
*
* @param packageIds List of packages. These are specifiesd in "load order", meaning
* later ones override the contents of earlier ones.
*
* @return @c true, if the list of packages is different than the one set previously.
*/
bool setPackages(de::StringList const &packageIds);

de::Block read(de::String const &lumpName) const;

private:
DENG2_PRIVATE(d)
};

} // namespace res

#endif // LIBDOOMSDAY_LUMPCATALOG_H
Expand Up @@ -43,6 +43,7 @@ class LIBDOOMSDAY_PUBLIC LumpDirectory
};

typedef de::dsize Pos;
static de::dsize const InvalidPos;

DENG2_ERROR(OffsetError);

Expand Down Expand Up @@ -72,8 +73,26 @@ class LIBDOOMSDAY_PUBLIC LumpDirectory
*/
de::duint32 crc32() const;

/**
* Checks if the lump directory has a specific lump. Performance is O(1) (hashed).
*
* @param lumpName Name of a lump.
*
* @return @c true, if the lump is in the directory.
*/
bool has(de::Block const &lumpName) const;

/**
* Finds the entry of a lump in the directory. If there are multiple lumps with
* the same name, this returns the last one in the directory. Performance is O(1)
* (hashed).
*
* @param lumpName Name of a lump.
*
* @return Lump entry information.
*/
LumpDirectory::Pos find(de::Block const &lumpName) const;

de::duint32 lumpSize(de::Block const &lumpName) const;

private:
Expand Down
105 changes: 105 additions & 0 deletions doomsday/apps/libdoomsday/src/resource/lumpcatalog.cpp
@@ -0,0 +1,105 @@
/** @file lumpcatalog.cpp
*
* @authors Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>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, see:
* http://www.gnu.org/licenses</small>
*/

#include "doomsday/resource/lumpcatalog.h"
#include "doomsday/resource/lumpdirectory.h"
#include "doomsday/resource/databundle.h"

#include <de/App>
#include <de/LinkFile>
#include <de/PackageLoader>
#include <utility>

using namespace de;

namespace res {

DENG2_PIMPL(LumpCatalog)
{
using Found = std::pair<DataBundle const *, LumpDirectory::Pos>;

StringList packageIds;
QList<DataBundle const *> bundles; /// @todo Should observe for deletion. -jk

Instance(Public *i) : Base(i) {}

void updateBundles()
{
bundles.clear();

for(auto const &pkg : packageIds)
{
// The package must be available as a file.
if(File const *file = App::packageLoader().select(pkg))
{
auto const *bundle = file->target().maybeAs<DataBundle>();
if(bundle && bundle->lumpDirectory())
{
bundles << bundle;
}
}
}
}

Found findLump(String const &name) const
{
Block const lumpName = name.toLatin1();
Found found { nullptr, LumpDirectory::InvalidPos };

// The last bundle is checked first.
for(int i = bundles.size() - 1; i >= 0; --i)
{
auto const pos = bundles.at(i)->lumpDirectory()->find(lumpName);
if(pos != LumpDirectory::InvalidPos)
{
found = Found(bundles.at(i), pos);
break;
}
}
return found;
}
};

LumpCatalog::LumpCatalog()
: d(new Instance(this))
{}

bool LumpCatalog::setPackages(StringList const &packageIds)
{
if(packageIds != d->packageIds)
{
d->packageIds = packageIds;
d->updateBundles();
return true;
}
return false;
}

Block LumpCatalog::read(String const &lumpName) const
{
Block data;
Instance::Found found = d->findLump(lumpName);
if(found.first)
{
auto const &entry = found.first->lumpDirectory()->entry(found.second);
data.copyFrom(*found.first, entry.offset, entry.size);
}
return data;
}

} // namespace res
20 changes: 16 additions & 4 deletions doomsday/apps/libdoomsday/src/resource/lumpdirectory.cpp
Expand Up @@ -26,12 +26,14 @@ using namespace de;

namespace res {

dsize const LumpDirectory::InvalidPos = dsize(-1);

DENG2_PIMPL_NOREF(LumpDirectory)
{
Type type = Invalid;
duint32 crc = 0;
QList<Entry> entries;
QHash<QByteArray, Entry *> index; // points to entries
QHash<QByteArray, int> index; // points to entries

void read(IByteArray const &source)
{
Expand Down Expand Up @@ -67,9 +69,9 @@ DENG2_PIMPL_NOREF(LumpDirectory)

// Make an index of all the lumps.
index.clear();
for(Entry &entry : entries)
for(int i = 0; i < entries.size(); ++i)
{
index.insert(entry.name, &entry);
index.insert(entries.at(i).name, i);
}
}
};
Expand Down Expand Up @@ -116,7 +118,7 @@ duint32 LumpDirectory::lumpSize(Block const &lumpName) const
auto found = d->index.constFind(lumpName);
if(found != d->index.constEnd())
{
return found.value()->size;
return d->entries.at(found.value()).size;
}
return 0;
}
Expand All @@ -126,4 +128,14 @@ bool LumpDirectory::has(Block const &lumpName) const
return d->index.contains(lumpName);
}

LumpDirectory::Pos LumpDirectory::find(Block const &lumpName) const
{
auto found = d->index.constFind(lumpName);
if(found != d->index.constEnd())
{
return found.value();
}
return InvalidPos;
}

} // namespace res

0 comments on commit d0c270a

Please sign in to comment.