Files
OpenVulkano/openVulkanoCpp/IO/Archive/MultiPartArchiveWriter.cpp

112 lines
3.8 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/.
*/
#include "MultiPartArchiveWriter.hpp"
#include "LibArchiveHelper.hpp"
#include <spdlog/fmt/fmt.h> //TODO replace with external fmt
#include <archive.h>
#include <archive_entry.h>
namespace openVulkanoCpp
{
MultiPartArchiveWriter::MultiPartArchiveWriter(const std::string& dir, const std::string& fileNamePattern,
const ArchiveConfiguration& archiveConfiguration,
size_t sizeLimit, bool lazyCreation,
const std::shared_ptr<spdlog::logger>& logger)
: m_fileSizeLimit(sizeLimit), m_archiveId(0), m_archiveConfig(archiveConfiguration)
, m_dir(dir), m_fileNamePattern(fileNamePattern), m_logger(logger), m_lazyCreation(lazyCreation)
{
if (!m_dir.empty() && !std::filesystem::exists(m_dir))
{
std::filesystem::create_directories(m_dir);
}
if (!lazyCreation) StartNewFile();
}
MultiPartArchiveWriter::~MultiPartArchiveWriter()
{
bool deleteLast = m_writer->GetTotalWrittenBytes() == 0;
m_writer = nullptr;
if (deleteLast) std::filesystem::remove(m_archives.back());
}
void MultiPartArchiveWriter::StartNewFile()
{
m_archives.push_back(m_dir / fmt::format(m_fileNamePattern, m_archiveId++));
#ifdef WIN32
m_writer = std::make_unique<ArchiveWriter>(m_archives.back().string().c_str(), m_archiveConfig, m_logger);
#else
m_writer = std::make_unique<ArchiveWriter>(m_archives.back().c_str(), m_archiveConfig, m_logger);
#endif
}
void MultiPartArchiveWriter::CheckSize(size_t size)
{
if (!m_writer || m_fileSizeLimit < m_writer->GetTotalWrittenBytes() + size)
{
StartNewFile();
}
}
bool MultiPartArchiveWriter::AddFile(const FileDescription& description, const void* buffer)
{
CheckSize(description.size);
return m_writer->AddFile(description, buffer);
}
bool MultiPartArchiveWriter::AddFile(const FileDescription& description, const std::vector<std::pair<const void*, size_t>>& buffers)
{
CheckSize(description.size);
return m_writer->AddFile(description, buffers);
}
bool MultiPartArchiveWriter::AddFile(const char* fileName, const char* inArchiveName)
{
std::unique_ptr<archive_entry, decltype(archive_entry_free)*> archiveEntry(archive_entry_new(), archive_entry_free);
std::unique_ptr<archive, decltype(archive_free)*> archiveDisk(archive_read_disk_new(), archive_free);
LibArchiveHelper::CheckError(archive_read_disk_open(archiveDisk.get(), fileName), archiveDisk.get(), m_logger);
LibArchiveHelper::CheckError(archive_read_next_header2(archiveDisk.get(), archiveEntry.get()), archiveDisk.get(), m_logger);
CheckSize(archive_entry_size(archiveEntry.get()));
return m_writer->AddFile(fileName, inArchiveName);
}
void MultiPartArchiveWriter::Move(const std::filesystem::path& newDir)
{
bool hasToMove = m_archives.size() > 1 || m_writer->GetTotalWrittenBytes() > 0;
m_writer = nullptr; // Close current archive
if (!newDir.empty() && !std::filesystem::exists(newDir))
{
std::filesystem::create_directories(newDir);
}
if (hasToMove)
{ // Move all existing archives
std::vector<std::filesystem::path> newArchivePaths;
newArchivePaths.reserve(m_archives.size() + 1);
for (const auto& file : m_archives)
{
newArchivePaths.push_back(newDir / file.filename());
std::filesystem::rename(file, newArchivePaths.back());
}
m_archives = std::move(newArchivePaths);
}
else
{
m_archiveId = 0;
std::filesystem::remove(m_archives.back());
m_archives.clear();
}
m_dir = newDir;
if (!m_lazyCreation) StartNewFile();
}
void MultiPartArchiveWriter::Split()
{
if (!m_writer || !m_writer->GetTotalWrittenBytes()) return; // Nothing has been written yet, no need to split file
m_writer = nullptr;
}
}