/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #pragma once #include #include #include #include "Base/Logger.hpp" namespace OpenVulkano { #ifdef _MSC_VER using mode_t = unsigned short; using ssize_t = int64_t; #endif namespace LibArchiveHelper { constexpr mode_t GetFileType(std::filesystem::file_type type) { switch (type) { case std::filesystem::file_type::regular: return AE_IFREG; case std::filesystem::file_type::directory: return AE_IFDIR; case std::filesystem::file_type::symlink: return AE_IFLNK; case std::filesystem::file_type::block: return AE_IFBLK; case std::filesystem::file_type::character: return AE_IFCHR; case std::filesystem::file_type::fifo: return AE_IFIFO; case std::filesystem::file_type::socket: return AE_IFSOCK; } return AE_IFMT; } constexpr std::filesystem::file_type GetFileType(mode_t type) { switch(type & AE_IFMT) { case AE_IFREG: return std::filesystem::file_type::regular; case AE_IFDIR: return std::filesystem::file_type::directory; case AE_IFLNK: return std::filesystem::file_type::symlink; case AE_IFBLK: return std::filesystem::file_type::block; case AE_IFCHR: return std::filesystem::file_type::character; case AE_IFIFO: return std::filesystem::file_type::fifo; case AE_IFSOCK: return std::filesystem::file_type::socket; } return std::filesystem::file_type::unknown; } template inline ssize_t CopyArchiveData(struct archive* archiveReader, struct archive* archiveWriter) { const void* buffer; size_t size; int64_t offset, r; while (true) { r = archive_read_data_block(archiveReader, &buffer, &size, &offset); if (r == ARCHIVE_EOF) return ARCHIVE_OK; if (r < ARCHIVE_OK) return r; if constexpr (BLOCK_WRITE) { r = archive_write_data_block(archiveWriter, buffer, size, offset); } else { r = archive_write_data(archiveWriter, buffer, size); } if (r < ARCHIVE_OK) return r; } } inline bool CheckError(long archiveResult, struct archive* arch, const Logger::Ptr& logger) { if (archiveResult >= ARCHIVE_OK) return true; spdlog::level::level_enum lvl = spdlog::level::level_enum::warn; if (archiveResult <= ARCHIVE_FATAL) lvl = spdlog::level::level_enum::critical; else if (archiveResult <= ARCHIVE_FAILED) lvl = spdlog::level::level_enum::err; const char* errorString = archive_error_string(arch); if (logger) logger->log(lvl, errorString ? errorString : "Unknown error while handling archive"); if (archiveResult == ARCHIVE_FAILED) throw std::runtime_error(errorString); return false; } } class LibArchiveEntryStreamBuffer final : public std::streambuf { private: struct archive* m_archive; char* m_buffer; size_t m_currentBlockSize; int64_t offset, r; bool ReadNextBlock() { const void* buffer; bool ok = archive_read_data_block(m_archive, &buffer, &m_currentBlockSize, &offset) == ARCHIVE_OK; m_buffer = static_cast(const_cast(buffer)); return ok; } public: LibArchiveEntryStreamBuffer(struct archive* arch) : m_archive(arch), m_currentBlockSize(0) {} int underflow() override { if (gptr() == egptr()) { if (ReadNextBlock()) { setg(m_buffer, m_buffer, m_buffer + m_currentBlockSize); } else { return std::char_traits::eof(); } } return std::char_traits::to_int_type(*this->gptr()); } }; }