114 lines
3.2 KiB
C++
114 lines
3.2 KiB
C++
/*
|
|
* 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 <archive.h>
|
|
#include <archive_entry.h>
|
|
#include <streambuf>
|
|
#include "Base/Logger.hpp"
|
|
|
|
namespace openVulkanoCpp
|
|
{
|
|
namespace LibArchiveHelper
|
|
{
|
|
constexpr mode_t FILE_TYPE_MAP[] = { AE_IFMT, AE_IFREG, AE_IFDIR, AE_IFLNK, AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK, 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;
|
|
}
|
|
|
|
constexpr mode_t GetFileType(std::filesystem::file_type type)
|
|
{
|
|
return FILE_TYPE_MAP[static_cast<signed char>(type)];
|
|
}
|
|
|
|
template<bool BLOCK_WRITE = false>
|
|
inline ssize_t CopyArchiveData(struct archive* archiveReader, struct archive* archiveWriter)
|
|
{
|
|
const void* buffer;
|
|
size_t size;
|
|
ssize_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(int 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);
|
|
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;
|
|
ssize_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<char*>(const_cast<void*>(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<char>::eof();
|
|
}
|
|
}
|
|
return std::char_traits<char>::to_int_type(*this->gptr());
|
|
}
|
|
};
|
|
}
|