archive/zzip: use std::shared_ptr instead of class RefCount

This commit is contained in:
Max Kellermann 2017-12-22 16:20:05 +01:00
parent e1c39f3fdc
commit 17558102f2

View File

@ -28,31 +28,37 @@
#include "../ArchiveVisitor.hxx" #include "../ArchiveVisitor.hxx"
#include "input/InputStream.hxx" #include "input/InputStream.hxx"
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "util/RefCount.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include <zzip/zzip.h> #include <zzip/zzip.h>
class ZzipArchiveFile final : public ArchiveFile { struct ZzipDir {
public:
RefCount ref;
ZZIP_DIR *const dir; ZZIP_DIR *const dir;
ZzipArchiveFile(ZZIP_DIR *_dir) explicit ZzipDir(Path path)
:dir(_dir) {} :dir(zzip_dir_open(path.c_str(), nullptr)) {
if (dir == nullptr)
throw FormatRuntimeError("Failed to open ZIP file %s",
path.c_str());
}
~ZzipArchiveFile() { ~ZzipDir() noexcept {
zzip_dir_close(dir); zzip_dir_close(dir);
} }
void Unref() { ZzipDir(const ZzipDir &) = delete;
if (ref.Decrement()) ZzipDir &operator=(const ZzipDir &) = delete;
delete this; };
}
class ZzipArchiveFile final : public ArchiveFile {
std::shared_ptr<ZzipDir> dir;
public:
ZzipArchiveFile(std::shared_ptr<ZzipDir> &&_dir)
:dir(std::move(_dir)) {}
virtual void Close() override { virtual void Close() override {
Unref(); delete this;
} }
virtual void Visit(ArchiveVisitor &visitor) override; virtual void Visit(ArchiveVisitor &visitor) override;
@ -66,21 +72,16 @@ public:
static ArchiveFile * static ArchiveFile *
zzip_archive_open(Path pathname) zzip_archive_open(Path pathname)
{ {
ZZIP_DIR *dir = zzip_dir_open(pathname.c_str(), nullptr); return new ZzipArchiveFile(std::make_shared<ZzipDir>(pathname));
if (dir == nullptr)
throw FormatRuntimeError("Failed to open ZIP file %s",
pathname.c_str());
return new ZzipArchiveFile(dir);
} }
inline void inline void
ZzipArchiveFile::Visit(ArchiveVisitor &visitor) ZzipArchiveFile::Visit(ArchiveVisitor &visitor)
{ {
zzip_rewinddir(dir); zzip_rewinddir(dir->dir);
ZZIP_DIRENT dirent; ZZIP_DIRENT dirent;
while (zzip_dir_read(dir, &dirent)) while (zzip_dir_read(dir->dir, &dirent))
//add only files //add only files
if (dirent.st_size > 0) if (dirent.st_size > 0)
visitor.VisitArchiveEntry(dirent.d_name); visitor.VisitArchiveEntry(dirent.d_name);
@ -89,15 +90,15 @@ ZzipArchiveFile::Visit(ArchiveVisitor &visitor)
/* single archive handling */ /* single archive handling */
struct ZzipInputStream final : public InputStream { struct ZzipInputStream final : public InputStream {
ZzipArchiveFile *archive; std::shared_ptr<ZzipDir> dir;
ZZIP_FILE *file; ZZIP_FILE *file;
ZzipInputStream(ZzipArchiveFile &_archive, const char *_uri, ZzipInputStream(const std::shared_ptr<ZzipDir> _dir, const char *_uri,
Mutex &_mutex, Cond &_cond, Mutex &_mutex, Cond &_cond,
ZZIP_FILE *_file) ZZIP_FILE *_file)
:InputStream(_uri, _mutex, _cond), :InputStream(_uri, _mutex, _cond),
archive(&_archive), file(_file) { dir(_dir), file(_file) {
//we are seekable (but its not recommendent to do so) //we are seekable (but its not recommendent to do so)
seekable = true; seekable = true;
@ -106,13 +107,10 @@ struct ZzipInputStream final : public InputStream {
size = z_stat.st_size; size = z_stat.st_size;
SetReady(); SetReady();
archive->ref.Increment();
} }
~ZzipInputStream() { ~ZzipInputStream() {
zzip_file_close(file); zzip_file_close(file);
archive->Unref();
} }
/* virtual methods from InputStream */ /* virtual methods from InputStream */
@ -125,12 +123,12 @@ InputStream *
ZzipArchiveFile::OpenStream(const char *pathname, ZzipArchiveFile::OpenStream(const char *pathname,
Mutex &mutex, Cond &cond) Mutex &mutex, Cond &cond)
{ {
ZZIP_FILE *_file = zzip_file_open(dir, pathname, 0); ZZIP_FILE *_file = zzip_file_open(dir->dir, pathname, 0);
if (_file == nullptr) if (_file == nullptr)
throw FormatRuntimeError("not found in the ZIP file: %s", throw FormatRuntimeError("not found in the ZIP file: %s",
pathname); pathname);
return new ZzipInputStream(*this, pathname, return new ZzipInputStream(dir, pathname,
mutex, cond, mutex, cond,
_file); _file);
} }