Add ArchiveWriter

This commit is contained in:
2020-12-09 21:20:19 +01:00
parent 74165a4968
commit 58da701354
4 changed files with 423 additions and 0 deletions

View File

@@ -0,0 +1,218 @@
/*
* 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/.
*/
#include "ArchiveWriter.hpp"
#include "LibArchiveHelper.hpp"
#include "Base/Utils.hpp"
#include <archive.h>
#include <archive_entry.h>
#include <iostream>
namespace openVulkanoCpp
{
namespace
{
constexpr int TYPE_MAP[] = { ARCHIVE_FORMAT_TAR, ARCHIVE_FORMAT_CPIO, ARCHIVE_FORMAT_ISO9660, ARCHIVE_FORMAT_ZIP, ARCHIVE_FORMAT_XAR, ARCHIVE_FORMAT_7ZIP, ARCHIVE_FORMAT_WARC, ARCHIVE_FORMAT_SHAR };
constexpr std::string_view TYPE_NAMES[] = { ".tar", ".cpio", ".iso", ".zip", ".xar", ".7z", ".warc", ".shar" };
constexpr int COMP_MAP[] = { ARCHIVE_FILTER_COMPRESS, ARCHIVE_FILTER_NONE, ARCHIVE_FILTER_GZIP, ARCHIVE_FILTER_BZIP2, ARCHIVE_FILTER_XZ, ARCHIVE_FILTER_LZ4, ARCHIVE_FILTER_ZSTD };
constexpr std::string_view COMP_NAMES[] = { ".Z", "", ".gz", ".bz2", ".xz", ".lz", ".zst" };
constexpr std::string_view TAR_SORTS[] = { ".tZ", ".tar", ".tgz", ".tbz2", ".txz", ".tlz", ".tzst" };
}
std::string ArchiveConfiguration::GetFileExtension() const
{
const std::string_view& tName = TYPE_NAMES[static_cast<int>(type)];
if (type == ArchiveType::TAR)
{
const std::string_view& cName = COMP_NAMES[static_cast<int>(compression)];
std::string extension;
extension.reserve(tName.length() + cName.length());
extension.append(tName).append(cName);
return extension;
}
return std::string(tName);
}
ArchiveConfiguration ArchiveConfiguration::FromFileName(const char* fileName)
{
std::string_view fName = fileName;
ArchiveConfiguration ac;
int tId = 0;
for(const std::string_view& tName : TYPE_NAMES)
{
if (tId > 0)
{
if (Utils::EndsWith(fName, tName))
{
ac.type = static_cast<ArchiveType>(tId);
return ac;
}
}
tId++;
}
tId = 0;
for(const std::string_view& tsName : TAR_SORTS)
{
if (Utils::EndsWith(fName, tsName))
{
ac.compression = static_cast<CompressionType>(tId);
return ac;
}
tId++;
}
tId = 0;
for(const std::string_view& cName : COMP_NAMES)
{
std::string tName(".tar");
tName.append(cName);
if (Utils::EndsWith(fName, tName))
{
ac.compression = static_cast<CompressionType>(tId);
return ac;
}
tId++;
}
return ac;
}
ArchiveWriter::ArchiveWriter(const char* fileName) : ArchiveWriter(fileName, ArchiveConfiguration::FromFileName(fileName))
{}
ArchiveWriter::ArchiveWriter(const char* fileName, ArchiveConfiguration archiveConfiguration)
: m_archive(archive_write_new()), m_archiveEntry(archive_entry_new())
{ //TODO error handling
archive_write_set_format(m_archive, TYPE_MAP[static_cast<int>(archiveConfiguration.type)]);
if (archiveConfiguration.type == ArchiveConfiguration::ArchiveType::TAR)
{
archive_write_add_filter(m_archive, COMP_MAP[static_cast<int>(archiveConfiguration.compression)]);
}
if (archiveConfiguration.compression != ArchiveConfiguration::CompressionType::NONE &&
archiveConfiguration.compressionLevel > 0)
{
std::string level = "compression-level=" + std::to_string(archiveConfiguration.compressionLevel);
archive_write_set_options(m_archive, level.c_str());
}
archive_write_open_filename(m_archive, fileName);
}
ArchiveWriter::~ArchiveWriter()
{
archive_entry_free(m_archiveEntry);
archive_write_free(m_archive);
}
void ArchiveWriter::Close()
{
archive_write_close(m_archive);
}
bool ArchiveWriter::AddFile(const char* fileName)
{
std::filesystem::path path(fileName);
if (std::filesystem::is_regular_file(path))
{
return AddFile(fileName, path.filename().c_str());
}
else if (std::filesystem::is_directory(path))
{
AddFiles(fileName, path.filename().c_str());
}
return false;
}
bool ArchiveWriter::AddFile(const char* fileName, const char* inArchiveName)
{
archive_entry_clear(m_archiveEntry);
std::unique_ptr<archive, decltype(archive_free)*> archiveDisk(archive_read_disk_new(), archive_free);
archive_entry_clear(m_archiveEntry);
archive_read_disk_open(archiveDisk.get(), fileName);
archive_read_next_header2(archiveDisk.get(), m_archiveEntry);
//archive_read_disk_entry_from_file(archiveDisk, m_archiveEntry, -1, nullptr);
archive_entry_set_pathname(m_archiveEntry, inArchiveName);
archive_write_header(m_archive, m_archiveEntry);
if (LibArchiveHelper::CopyArchiveData(archiveDisk.get(), m_archive) != ARCHIVE_OK)
{
//TODO handle error
}
return true;
}
bool ArchiveWriter::AddFile(const char* inArchiveName, const void* buffer, size_t length)
{
FileDescription description = FileDescription::MakeDescriptionForFile(inArchiveName, length);
return AddFile(description, buffer);
}
bool ArchiveWriter::AddFile(const FileDescription& description, const void* buffer)
{
WriteHeader(description);
return archive_write_data(m_archive, buffer, description.size) == ARCHIVE_OK;
}
bool ArchiveWriter::AddFile(const char* fileName, const std::vector<std::pair<const void*, size_t>>& buffers)
{
size_t size = 0;
for(const auto& buffer : buffers)
{
if (buffer.first == nullptr) continue;
size += buffer.second;
}
FileDescription description = FileDescription::MakeDescriptionForFile(fileName, size);
return AddFile(description, buffers);
}
bool ArchiveWriter::AddFile(const FileDescription& description, const std::vector<std::pair<const void*, size_t>>& buffers)
{
WriteHeader(description);
for(const auto& buffer : buffers)
{
if (buffer.first == nullptr) continue;
if (archive_write_data(m_archive, buffer.first, buffer.second) != ARCHIVE_OK)
{
return false;
}
}
return true;
}
void ArchiveWriter::WriteHeader(const FileDescription& fileDescription)
{
archive_entry_clear(m_archiveEntry);
archive_entry_set_pathname_utf8(m_archiveEntry, fileDescription.path.c_str());
archive_entry_set_size(m_archiveEntry, fileDescription.size);
archive_entry_set_filetype(m_archiveEntry, LibArchiveHelper::GetFileType(fileDescription.type));
archive_entry_set_perm(m_archiveEntry, static_cast<mode_t>(fileDescription.permissions));
archive_entry_set_ctime(m_archiveEntry, fileDescription.createTime, 0);
archive_entry_set_mtime(m_archiveEntry, fileDescription.modTime, 0);
archive_write_header(m_archive, m_archiveEntry);
}
bool ArchiveWriter::AddFiles(const char* dirName)
{
return AddFiles(dirName, "");
}
bool ArchiveWriter::AddFiles(const char* dirName, const char* inArchiveDirName)
{
return AddFiles(std::filesystem::path(dirName), std::string(inArchiveDirName));
}
bool ArchiveWriter::AddFiles(const std::filesystem::path& dirName, const std::string& inArchiveDirName)
{
AddFile(dirName.c_str(), inArchiveDirName.c_str());
for(const auto& entry : std::filesystem::directory_iterator(dirName))
{
std::string fPath = inArchiveDirName + "/" + entry.path().filename().native();
if (entry.is_directory()) AddFiles(entry, fPath);
else AddFile(entry.path().c_str(), fPath.c_str());
}
return true;
}
}