Implement zip::read_file() – Read file in archive; add test.
Also added zip::open_file() and zip::close_file() to deduplicate code.
This commit is contained in:
parent
6334b7051f
commit
e773d4b78a
|
@ -80,7 +80,10 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
for (const auto &entry : epubgrep::zip::list(file))
|
||||
{
|
||||
cout << " " << entry << '\n';
|
||||
cout << " " << entry;
|
||||
cout << "\n CONTENT:\n";
|
||||
cout << "START" << epubgrep::zip::read_file(file, entry)
|
||||
<< "END\n";
|
||||
}
|
||||
}
|
||||
catch (const epubgrep::zip::exception &e)
|
||||
|
|
73
src/zip.cpp
73
src/zip.cpp
|
@ -24,6 +24,8 @@
|
|||
#include <fmt/format.h>
|
||||
#include <fmt/ostream.h> // For compatibility with fmt 4.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -35,16 +37,7 @@ using fmt::format;
|
|||
|
||||
std::vector<std::string> list(const fs::path &filepath)
|
||||
{
|
||||
auto *zipfile{archive_read_new()};
|
||||
archive_read_support_filter_all(zipfile);
|
||||
archive_read_support_format_all(zipfile);
|
||||
|
||||
auto result{archive_read_open_filename(zipfile, filepath.c_str(), 10240)};
|
||||
if (result != ARCHIVE_OK)
|
||||
{
|
||||
throw exception{format(translate("Could not open {0:s}.").str(),
|
||||
filepath.string())};
|
||||
}
|
||||
auto *zipfile{open_file(filepath)};
|
||||
|
||||
struct archive_entry *entry{};
|
||||
std::vector<std::string> toc;
|
||||
|
@ -53,15 +46,69 @@ std::vector<std::string> list(const fs::path &filepath)
|
|||
toc.emplace_back(archive_entry_pathname_utf8(entry));
|
||||
archive_read_data_skip(zipfile);
|
||||
}
|
||||
close_file(zipfile, filepath);
|
||||
|
||||
result = archive_read_free(zipfile);
|
||||
return toc;
|
||||
}
|
||||
|
||||
std::string read_file(const fs::path &filepath, std::string_view entry_path)
|
||||
{
|
||||
auto *zipfile{open_file(filepath)};
|
||||
|
||||
struct archive_entry *entry{};
|
||||
while (archive_read_next_header(zipfile, &entry) == ARCHIVE_OK)
|
||||
{
|
||||
const auto *path{archive_entry_pathname_utf8(entry)};
|
||||
if (std::strcmp(path, entry_path.data()) == 0)
|
||||
{
|
||||
const auto length{static_cast<size_t>(archive_entry_size(entry))};
|
||||
std::string filecontents;
|
||||
filecontents.resize(length);
|
||||
auto result_length{static_cast<size_t>(
|
||||
archive_read_data(zipfile, &filecontents[0], length))};
|
||||
|
||||
if (result_length != length)
|
||||
{
|
||||
throw exception{
|
||||
format(translate("Could not read {0:s} in {1:s}.").str(),
|
||||
entry_path, filepath.string())};
|
||||
}
|
||||
|
||||
return filecontents;
|
||||
}
|
||||
archive_read_data_skip(zipfile);
|
||||
}
|
||||
|
||||
close_file(zipfile, filepath);
|
||||
|
||||
throw exception{format(translate("{0:s} not found in {1:s}.").str(),
|
||||
entry_path, filepath.string())};
|
||||
}
|
||||
|
||||
struct archive *open_file(const fs::path &filepath)
|
||||
{
|
||||
auto *zipfile{archive_read_new()};
|
||||
archive_read_support_filter_all(zipfile);
|
||||
archive_read_support_format_zip(zipfile);
|
||||
|
||||
auto result{archive_read_open_filename(zipfile, filepath.c_str(), 10240)};
|
||||
if (result != ARCHIVE_OK)
|
||||
{
|
||||
throw exception{format(translate("Could not open {0:s}.").str(),
|
||||
filepath.string())};
|
||||
}
|
||||
|
||||
return zipfile;
|
||||
}
|
||||
|
||||
void close_file(struct archive *zipfile, const fs::path &filepath)
|
||||
{
|
||||
auto result{archive_read_free(zipfile)};
|
||||
if (result != ARCHIVE_OK)
|
||||
{
|
||||
throw exception{format(translate("Could not close {0:s}.").str(),
|
||||
filepath.string())};
|
||||
}
|
||||
|
||||
return toc;
|
||||
}
|
||||
|
||||
} // namespace epubgrep::zip
|
||||
|
|
12
src/zip.hpp
12
src/zip.hpp
|
@ -19,8 +19,11 @@
|
|||
|
||||
#include "fs-compat.hpp"
|
||||
|
||||
#include <archive.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace epubgrep::zip
|
||||
|
@ -29,6 +32,15 @@ namespace epubgrep::zip
|
|||
//! List the contents of a zip file.
|
||||
std::vector<std::string> list(const fs::path &filepath);
|
||||
|
||||
//! Read a file from a zip archive.
|
||||
std::string read_file(const fs::path &filepath, std::string_view entry_path);
|
||||
|
||||
//! Open zip file and return handle.
|
||||
struct archive *open_file(const fs::path &filepath);
|
||||
|
||||
//! Close zip file.
|
||||
void close_file(struct archive *zipfile, const fs::path &filepath);
|
||||
|
||||
// It's std::runtime_error, but with another name.
|
||||
class exception : public std::runtime_error
|
||||
{
|
||||
|
|
BIN
tests/test.zip
BIN
tests/test.zip
Binary file not shown.
72
tests/test_zip.cpp
Normal file
72
tests/test_zip.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "fs-compat.hpp"
|
||||
#include "zip.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <clocale>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
SCENARIO("Zip file handling works")
|
||||
{
|
||||
GIVEN("Our test zip file")
|
||||
{
|
||||
fs::path zipfile{"test.zip"};
|
||||
std::setlocale(LC_CTYPE, ""); // Needed for utf-8 support in libarchive.
|
||||
bool exception{false};
|
||||
|
||||
REQUIRE(fs::exists(zipfile));
|
||||
|
||||
SECTION("list() doesn't fail and returns the right file list")
|
||||
{
|
||||
std::vector<std::string> filelist;
|
||||
|
||||
WHEN("We list the file contents")
|
||||
{
|
||||
try
|
||||
{
|
||||
filelist = epubgrep::zip::list(zipfile);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN("No exception is thrown")
|
||||
AND_THEN("It returns the TOC correctly")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(filelist.at(0) == "test folder/");
|
||||
REQUIRE(filelist.at(1) == "test folder/test file");
|
||||
REQUIRE(filelist.at(2) == "test folder/😊");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("read_file() doesn't fail and returns the right file contents")
|
||||
{
|
||||
std::string filecontents;
|
||||
|
||||
WHEN("We list the file contents")
|
||||
{
|
||||
try
|
||||
{
|
||||
filecontents = epubgrep::zip::read_file(zipfile,
|
||||
"test folder/😊");
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN("No exception is thrown")
|
||||
AND_THEN("It returns the file contents correctly")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(filecontents == "📖\n\n📘📗📙\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
#include "fs-compat.hpp"
|
||||
#include "zip.hpp"
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include <clocale>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
SCENARIO("epubgrep::zip::list() doesn't fail and returns the right file list")
|
||||
{
|
||||
std::setlocale(LC_CTYPE, ""); // Needed for utf-8 support in libarchive.
|
||||
bool exception{false};
|
||||
std::vector<std::string> filelist;
|
||||
|
||||
GIVEN("Our test zip file")
|
||||
{
|
||||
fs::path zipfile{"test.zip"};
|
||||
|
||||
REQUIRE(fs::exists(zipfile));
|
||||
|
||||
WHEN("We list the file contents")
|
||||
{
|
||||
try
|
||||
{
|
||||
filelist = epubgrep::zip::list(zipfile);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN("No exception is thrown")
|
||||
AND_THEN("It returns the file contents correctly")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(filelist.at(0) == "test folder/");
|
||||
REQUIRE(filelist.at(1) == "test folder/test file");
|
||||
REQUIRE(filelist.at(2) == "test folder/😊");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user