Filesystem: Optimize RGSSAD file enumeration
Finally got around to nuking that ugly pile of shit that was previously there for PhysFS file enumeration because filepath cache generation with unencrypted game files + archive + RTP has started taking around 6 seconds. Thank $DEITY.
This commit is contained in:
parent
28ff5cd33c
commit
06f5a06f67
|
@ -27,6 +27,7 @@
|
||||||
#include "physfs.h"
|
#include "physfs.h"
|
||||||
|
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QSet>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
#include "stdio.h"
|
#include "stdio.h"
|
||||||
|
@ -67,8 +68,14 @@ typedef QList<QByteArray> QByteList;
|
||||||
struct RGSS_archiveData
|
struct RGSS_archiveData
|
||||||
{
|
{
|
||||||
PHYSFS_Io *archiveIo;
|
PHYSFS_Io *archiveIo;
|
||||||
|
|
||||||
|
/* Maps: file path
|
||||||
|
* to: entry data */
|
||||||
QHash<QByteArray, RGSS_entryData> entryHash;
|
QHash<QByteArray, RGSS_entryData> entryHash;
|
||||||
QHash<QByteArray, bool> dirHash;
|
|
||||||
|
/* Maps: directory path,
|
||||||
|
* to: list of contained entries */
|
||||||
|
QHash<QByteArray, QSet<QByteArray> > dirHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -344,6 +351,9 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
|
||||||
|
|
||||||
uint32_t magic = RGSS_MAGIC;
|
uint32_t magic = RGSS_MAGIC;
|
||||||
|
|
||||||
|
/* Top level entry list */
|
||||||
|
QSet<QByteArray> &topLevel = data->dirHash["."];
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
/* Read filename length,
|
/* Read filename length,
|
||||||
|
@ -377,13 +387,33 @@ RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
|
||||||
|
|
||||||
data->entryHash.insert(nameBuf, entry);
|
data->entryHash.insert(nameBuf, entry);
|
||||||
|
|
||||||
/* Test for new folder */
|
/* Check for top level entries */
|
||||||
|
for (i = 0; i < nameLen; ++i)
|
||||||
|
{
|
||||||
|
bool slash = nameBuf[i] == '/';
|
||||||
|
if (!slash && i+1 < nameLen)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (slash)
|
||||||
|
nameBuf[i] = '\0';
|
||||||
|
|
||||||
|
topLevel.insert(nameBuf);
|
||||||
|
|
||||||
|
if (slash)
|
||||||
|
nameBuf[i] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for more entries */
|
||||||
for (i = nameLen; i > 0; i--)
|
for (i = nameLen; i > 0; i--)
|
||||||
if (nameBuf[i] == '/')
|
if (nameBuf[i] == '/')
|
||||||
{
|
{
|
||||||
nameBuf[i] = '\0';
|
nameBuf[i] = '\0';
|
||||||
if (!data->dirHash.contains(nameBuf))
|
|
||||||
data->dirHash.insert(nameBuf, true);
|
const char *dir = nameBuf;
|
||||||
|
const char *entry = &nameBuf[i+1];
|
||||||
|
|
||||||
|
QSet<QByteArray> &entryList = data->dirHash[dir];
|
||||||
|
entryList.insert(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
io->seek(io, entry.offset + entry.size);
|
io->seek(io, entry.offset + entry.size);
|
||||||
|
@ -399,34 +429,16 @@ RGSS_enumerateFiles(void *opaque, const char *dirname,
|
||||||
{
|
{
|
||||||
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
|
RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
|
||||||
|
|
||||||
char dirBuf[512];
|
QByteArray _dirname(dirname);
|
||||||
QByteList keys = data->entryHash.keys();
|
|
||||||
keys += data->dirHash.keys();
|
|
||||||
|
|
||||||
Q_FOREACH (const QByteArray &filename, keys)
|
if (!data->dirHash.contains(_dirname))
|
||||||
{
|
return;
|
||||||
/* Get the filename directory part */
|
|
||||||
strncpy(dirBuf, filename.constData(), sizeof(dirBuf));
|
|
||||||
|
|
||||||
/* Extract path and basename */
|
const QSet<QByteArray> &entries = data->dirHash.value(_dirname);
|
||||||
const char *dirpath = ".";
|
|
||||||
char *basename = dirBuf;
|
|
||||||
|
|
||||||
for (int i = filename.size(); i >= 0; i--)
|
QSet<QByteArray>::const_iterator iter;
|
||||||
if (dirBuf[i] == '/')
|
for (iter = entries.begin(); iter != entries.end(); ++iter)
|
||||||
{
|
cb(callbackdata, origdir, iter->constData());
|
||||||
dirBuf[i] = '\0';
|
|
||||||
dirpath = dirBuf;
|
|
||||||
|
|
||||||
basename = &dirBuf[i+1];
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compare to provided dirname */
|
|
||||||
if (strcmp(dirpath, dirname) == 0)
|
|
||||||
cb(callbackdata, origdir, basename);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PHYSFS_Io*
|
static PHYSFS_Io*
|
||||||
|
@ -716,12 +728,13 @@ static void cacheEnumCB(void *d, const char *origdir,
|
||||||
else
|
else
|
||||||
strncpy(buf, fname, sizeof(buf));
|
strncpy(buf, fname, sizeof(buf));
|
||||||
|
|
||||||
QByteArray mixedCase = buf;
|
QByteArray mixedCase(buf);
|
||||||
|
|
||||||
QByteArray lowerCase = mixedCase;
|
for (char *p = buf; *p; ++p)
|
||||||
for (char *p = lowerCase.data(); *p; ++p)
|
|
||||||
*p = tolower(*p);
|
*p = tolower(*p);
|
||||||
|
|
||||||
|
QByteArray lowerCase(buf);
|
||||||
|
|
||||||
p->pathCache.insert(lowerCase, mixedCase);
|
p->pathCache.insert(lowerCase, mixedCase);
|
||||||
|
|
||||||
PHYSFS_enumerateFilesCallback(mixedCase.constData(), cacheEnumCB, p);
|
PHYSFS_enumerateFilesCallback(mixedCase.constData(), cacheEnumCB, p);
|
||||||
|
|
Loading…
Reference in New Issue