summaryrefslogtreecommitdiff
path: root/src/archive.cpp
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-09-18 21:59:54 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-09-18 21:59:54 -0500
commitfa4b4097d3283e1d6e6376c70910e245f0b1f6ec (patch)
tree74dff4ded82d3f4854b3f10d5dd2e5be1f69b95e /src/archive.cpp
parent04dbfdc97e94e6f477675b9d3135164752a7cfef (diff)
Save progress of qt6 implementation.
Diffstat (limited to 'src/archive.cpp')
-rw-r--r--src/archive.cpp136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/archive.cpp b/src/archive.cpp
new file mode 100644
index 0000000..0339d85
--- /dev/null
+++ b/src/archive.cpp
@@ -0,0 +1,136 @@
+#include "archive.hpp"
+
+#include "main_window.hpp"
+
+#include <algorithm>
+
+namespace getsuyomi {
+
+ZipArchive::ZipArchive(const QString& filename)
+{
+ auto filenameUtf8 = filename.toUtf8();
+ qDebug("Open file %s", filenameUtf8.data());
+ int err;
+ m_archive = zip_open(filenameUtf8.data(), 0, &err);
+ if (m_archive == nullptr) {
+ zip_error_t error;
+ zip_error_init_with_code(&error, err);
+ qCritical("%s: cannot open zip archive '%s': %s", AppName, filenameUtf8.data(), zip_error_strerror(&error));
+ zip_error_fini(&error);
+ throw std::runtime_error("Bad zip file");
+ }
+
+ populate();
+}
+
+void ZipArchive::populate()
+{
+ auto numEntries = zip_get_num_entries(m_archive, ZIP_FL_UNCHANGED);
+ qDebug("%zu pages", numEntries);
+
+ struct NameIndex {
+ std::string name;
+ size_t index;
+ size_t filesize;
+ };
+
+ std::vector<NameIndex> nameIndices{};
+ nameIndices.reserve(numEntries);
+ m_pages.reserve(numEntries);
+
+ for (size_t idx = 0; idx < numEntries; ++idx) {
+ struct zip_stat stats;
+
+ auto status = zip_stat_index(m_archive, idx, 0, &stats);
+ static_assert(ZIP_STAT_NAME != 0);
+ static_assert(ZIP_STAT_SIZE != 0);
+ static_assert(ZIP_STAT_INDEX != 0);
+ // auto* nameCString = zip_get_name(m_archive, idx, ZIP_FL_ENC_RAW);
+ auto* nameCString = stats.name;
+ if (nameCString == nullptr) {
+ zip_error_t* error = zip_get_error(m_archive);
+ qWarning("cannot get name %s", zip_error_strerror(error));
+ continue;
+ }
+ std::string name{nameCString};
+ if (name.empty() || name.back() == '/') {
+ qDebug("Directory %s", name.empty() ? "N/A" : nameCString);
+ continue;
+ }
+
+ nameIndices.emplace_back(NameIndex{name, idx, stats.size});
+ m_pages.emplace_back(std::nullopt);
+ }
+
+ std::sort(nameIndices.begin(), nameIndices.end(), [](const auto& lhs, const auto& rhs) {
+ return std::lexicographical_compare(lhs.name.begin(), lhs.name.end(), rhs.name.begin(), rhs.name.end());
+ });
+
+ m_sortedIndices.reserve(nameIndices.size());
+ m_filenames.reserve(nameIndices.size());
+ m_fileSizes.reserve(nameIndices.size());
+
+ for (const auto& nameIndex : nameIndices) {
+ m_sortedIndices.push_back(nameIndex.index);
+ m_filenames.push_back(nameIndex.name);
+ m_fileSizes.push_back(nameIndex.filesize);
+ }
+}
+
+ZipArchive::~ZipArchive()
+{
+ if (m_archive != nullptr) {
+ zip_discard(m_archive);
+ m_archive = nullptr;
+ }
+}
+
+ArchiveResult ZipArchive::getPage(size_t page)
+{
+ qDebug("Getting page %zu", page);
+ if (page > m_sortedIndices.size()) {
+ return ArchiveResult::error(ArchiveError::BadIndex);
+ }
+
+ if (m_pages[page] != std::nullopt) {
+ qDebug("Page found %zu", page);
+ return ArchiveResult::okay(std::cref(*m_pages[page]));
+ }
+
+ auto* file = zip_fopen_index(m_archive, m_sortedIndices[page], 0);
+ if (file == nullptr) {
+ zip_error_t* error = zip_get_error(m_archive);
+ qWarning("cannot get file name %s: %s", m_filenames[page].data(), zip_error_strerror(error));
+ return ArchiveResult::error(ArchiveError::ZipError);
+ }
+
+ QByteArray data;
+ data.resize(m_fileSizes[page]);
+ auto index = m_sortedIndices[page];
+
+ qDebug("Reading in page data");
+ auto bytesRead = zip_fread(file, data.data(), data.size());
+ zip_fclose(file);
+ file = nullptr;
+
+ if (bytesRead != data.size()) {
+ return ArchiveResult::error(ArchiveError::ZipError);
+ }
+
+ m_pages[page] = QImage();
+ qDebug("Loading QImage from page data");
+ auto loaded = m_pages[page]->loadFromData(data);
+ if (!loaded) {
+ qWarning("Failed to load QImage");
+ m_pages[page] = std::nullopt;
+ return ArchiveResult::error(ArchiveError::BadData);
+ }
+
+ return ArchiveResult::okay(std::cref(*m_pages[page]));
+}
+
+size_t ZipArchive::numPages() const {
+ return m_pages.size();
+}
+
+} // namespace getsuyomi