Allow uncompressed files in zip archives

This commit is contained in:
2023-11-19 23:49:11 +01:00
parent 761d8d3d33
commit 681fc00a68
9 changed files with 98 additions and 3 deletions

View File

@@ -32,8 +32,6 @@ namespace OpenVulkano
[[nodiscard]] int GetLibArchiveArchiveType() const;
[[nodiscard]] int GetLibArchiveCompressionType() const;
[[nodiscard]] constexpr bool AllowsUnknownFileSize() const { return type == ArchiveType::ZIP; }
};
namespace ArchiveConfig

View File

@@ -33,6 +33,7 @@ namespace OpenVulkano
[[nodiscard]] constexpr bool operator!=(ArchiveType rhs) const { return m_type != rhs.m_type; }
[[nodiscard]] constexpr explicit operator int() const { return m_type; }
[[nodiscard]] constexpr operator Type() const { return m_type; }
[[nodiscard]] static constexpr std::optional<ArchiveType> FromExtension(std::string_view fName)
{

View File

@@ -7,6 +7,7 @@
#include "ArchiveWriter.hpp"
#include "LibArchiveHelper.hpp"
#include "ArchiveStreamBufferWriter.hpp"
#include "SimpleFileTypeShouldCompressChecker.hpp"
#include <archive.h>
#include <archive_entry.h>
#include <iostream>
@@ -16,6 +17,7 @@ namespace OpenVulkano
ArchiveWriter::ArchiveWriter(const char* fileName, ArchiveConfiguration archiveConfiguration, const std::shared_ptr<spdlog::logger>& logger)
: ArchiveBase(archive_write_new(), archive_entry_new(), logger)
, m_archiveConfig(archiveConfiguration)
, m_shouldCompress(&SimpleFileTypeShouldCompressChecker)
{ //TODO error handling
ChkErr(archive_write_set_format(m_archive, archiveConfiguration.GetLibArchiveArchiveType()));
if (archiveConfiguration.type == ArchiveType::TAR)
@@ -87,6 +89,11 @@ namespace OpenVulkano
void ArchiveWriter::WriteHeader(const FileDescription& fileDescription)
{
if (m_asBuffer) { m_asBuffer->Close(); m_asBuffer = nullptr; }
if (m_archiveConfig.type.AllowsMixedCompressionLevels())
{
if (m_shouldCompress(fileDescription)) SetCompressed();
else SetUncompressed();
}
archive_entry_clear(m_archiveEntry);
archive_entry_set_pathname_utf8(m_archiveEntry, fileDescription.path.c_str());
if (fileDescription.size != FileDescription::UNKNOWN_SIZE)
@@ -95,7 +102,7 @@ namespace OpenVulkano
}
else
{
if (!m_archiveConfig.AllowsUnknownFileSize())
if (!m_archiveConfig.type.AllowsUnknownFileSize())
throw std::invalid_argument("Only ZIP files allow files of unknown size");
archive_entry_unset_size(m_archiveEntry);
}
@@ -106,4 +113,26 @@ namespace OpenVulkano
ChkErr(archive_write_header(m_archive, m_archiveEntry));
m_bytesWritten += fileDescription.size;
}
void ArchiveWriter::SetUncompressed()
{
if (!m_lastCompressed) return;
m_lastCompressed = false;
switch (m_archiveConfig.type)
{
case ArchiveType::ZIP: ChkErr(archive_write_zip_set_compression_store(m_archive));
default: ;
}
}
void ArchiveWriter::SetCompressed()
{
if (m_lastCompressed) return;
m_lastCompressed = true;
switch (m_archiveConfig.type)
{
case ArchiveType::ZIP: ChkErr(archive_write_zip_set_compression_deflate(m_archive));
default: ;
}
}
}

View File

@@ -22,6 +22,8 @@ namespace OpenVulkano
ArchiveConfiguration m_archiveConfig;
size_t m_bytesWritten = 0;
ArchiveOStream::ASBufferPtr m_asBuffer = nullptr;
bool m_lastCompressed = true;
std::function<bool(const FileDescription&)> m_shouldCompress;
public:
ArchiveWriter(const char* fileName, const std::shared_ptr<spdlog::logger>& logger = nullptr)
@@ -39,7 +41,13 @@ namespace OpenVulkano
bool AddFile(const char* fileName, const char* inArchiveName) override;
[[nodiscard]] ArchiveOStream AddFileStream(const FileDescription& description) override;
void SetShouldCompressFunction(const std::function<bool(const FileDescription&)>& shouldComp) override { m_shouldCompress = shouldComp; }
private:
void WriteHeader(const FileDescription& fileDescription);
void SetUncompressed();
void SetCompressed();
};
}

View File

@@ -8,6 +8,7 @@
#include "ArchiveOStream.hpp"
#include "IO/FileDescription.hpp"
#include <functional>
#include <vector>
namespace OpenVulkano
@@ -20,6 +21,8 @@ namespace OpenVulkano
public:
virtual ~IArchiveWriter() = default;
virtual void SetShouldCompressFunction(const std::function<bool(const FileDescription&)>& shouldComp) = 0;
virtual bool AddFile(const FileDescription& description, const void* buffer) = 0;
virtual bool AddFile(const FileDescription& description, const std::vector<std::pair<const void*, size_t>>& buffers) = 0;
virtual bool AddFile(const char* fileName, const char* inArchiveName) = 0;

View File

@@ -41,6 +41,7 @@ namespace OpenVulkano
#else
m_writer = std::make_unique<ArchiveWriter>(m_archives.back().c_str(), m_archiveConfig, m_logger);
#endif
if (m_shouldCompress) m_writer->SetShouldCompressFunction(m_shouldCompress);
}
void MultiPartArchiveWriter::CheckSize(size_t size)
@@ -114,4 +115,10 @@ namespace OpenVulkano
if (!m_writer || !m_writer->GetTotalWrittenBytes()) return; // Nothing has been written yet, no need to split file
m_writer = nullptr;
}
void MultiPartArchiveWriter::SetShouldCompressFunction(const std::function<bool(const FileDescription&)>& shouldComp)
{
if (m_writer) m_writer->SetShouldCompressFunction(shouldComp);
m_shouldCompress = shouldComp;
}
}

View File

@@ -22,6 +22,7 @@ namespace OpenVulkano
std::unique_ptr<ArchiveWriter> m_writer;
std::shared_ptr<spdlog::logger> m_logger;
std::vector<std::filesystem::path> m_archives;
std::function<bool(const FileDescription&)> m_shouldCompress;
bool m_lazyCreation;
void StartNewFile();
@@ -39,6 +40,8 @@ namespace OpenVulkano
using IArchiveWriter::AddFile;
[[nodiscard]] virtual ArchiveOStream AddFileStream(const FileDescription& description) override;
void SetShouldCompressFunction(const std::function<bool(const FileDescription&)>& shouldComp) override;
void SetLogger(const std::shared_ptr<spdlog::logger>& logger) { m_logger = logger; }
[[nodiscard]] std::shared_ptr<spdlog::logger> GetLogger() const { return m_logger; }

View File

@@ -0,0 +1,32 @@
/*
* 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 "SimpleFileTypeShouldCompressChecker.hpp"
#include "Base/Utils.hpp"
#include <set>
namespace OpenVulkano
{
namespace
{
const std::set<std::string_view> INCOMPRESSIBLE_TYPES = {
// Image formats
"jpg", "jpeg", "png",
// Video formats
"mp4",
// Audio formats
"mp3", "aac", "ac3",
// Other
};
}
bool SimpleFileTypeShouldCompressChecker(const FileDescription& fileDescription)
{
auto [fName, fType] = Utils::SplitAtLastOccurrence(fileDescription.path, '.');
std::transform(fType.begin(), fType.end(), fType.begin(), ::tolower); // fType to lowercase
return !INCOMPRESSIBLE_TYPES.count(fType);
}
}

View File

@@ -0,0 +1,14 @@
/*
* 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 "IO/FileDescription.hpp"
namespace OpenVulkano
{
bool SimpleFileTypeShouldCompressChecker(const FileDescription& fileDescription);
}