Faster ZIP access by indexing all files

This commit is contained in:
yvt 2014-03-16 00:39:56 +09:00
parent 18f8405aae
commit 2fbc7b573c
2 changed files with 56 additions and 5 deletions

View File

@ -304,6 +304,31 @@ namespace spades {
}
currentStream = NULL;
if(unzGoToFirstFile(zip) != UNZ_OK) {
SPRaise("There was a problem while seeking the zip file to the first file.");
}
// create list of files
do{
char buf[513];
buf[512] = 0;
unzGetCurrentFileInfo(zip, nullptr,
buf, 512, nullptr, 0, nullptr, 0);
for(char *ptr = buf; *ptr; ptr++) {
if(*ptr == '\\') *ptr = '/';
else
*ptr = tolower(*ptr);
}
unz_file_pos pos;
if(unzGetFilePos(zip, &pos) != UNZ_OK) {
SPRaise("unzGetFilePos failed");
}
files.insert(std::make_pair(buf, pos));
}while(unzGoToNextFile(zip) == UNZ_OK);
}
ZipFileSystem::~ZipFileSystem() {
@ -322,7 +347,7 @@ namespace spades {
currentStream->ForceCloseUnzipFile();
}
if(unzLocateFile(zip, fn, 2) != UNZ_OK){
if(!MoveToFile(fn)) {
SPFileNotFound(fn);
}
@ -389,6 +414,7 @@ namespace spades {
SPRaise("There was a problem while seeking the zip file to the first file.");
}
// FIXME: use `files` for faster search?
std::vector<std::string> lst;
size_t ln = strlen(path);
do{
@ -419,17 +445,36 @@ namespace spades {
return lst;
}
bool ZipFileSystem::FileExists(const char *fn) {
bool ZipFileSystem::MoveToFile(const char *fn) {
SPADES_MARK_FUNCTION();
if(currentStream){
currentStream->ForceCloseUnzipFile();
std::string f = fn;
for(std::size_t i = 0; i < f.size(); i++) {
if(f[i] == '\\') f[i] = '/';
else f[i] = tolower(f[i]);
}
if(unzLocateFile(zip, fn, 2) != UNZ_OK){
auto it = files.find(f);
if(it == files.end()) {
return false;
}
if(unzGoToFilePos(zip, &it->second) != UNZ_OK) {
SPRaise("Failed to seek to the requested file.");
}
return true;
}
bool ZipFileSystem::FileExists(const char *fn) {
SPADES_MARK_FUNCTION();
std::string f = fn;
for(std::size_t i = 0; i < f.size(); i++) {
if(f[i] == '\\') f[i] = '/';
else f[i] = tolower(f[i]);
}
return files.find(f) != files.end();
}
}

View File

@ -22,11 +22,14 @@
#include "IFileSystem.h"
#include <stdint.h>
#include <map>
#include <string>
extern "C"{
typedef void *unzFile;
struct zlib_filefunc_def_s;
typedef struct zlib_filefunc_def_s zlib_filefunc_def;
struct unz_file_pos_s;
}
namespace spades {
@ -38,6 +41,8 @@ namespace spades {
bool autoClose;
unzFile zip;
std::map<std::string, unz_file_pos_s> files;
ZipFileInputStream *currentStream;
uint64_t cursorPos;
@ -63,6 +68,7 @@ namespace spades {
ZipFileHandle *h);
zlib_filefunc_def CreateZLibFileFunc();
bool MoveToFile(const char *);
public:
ZipFileSystem(IStream *, bool autoClose = true);
virtual ~ZipFileSystem();