/* * 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 "ArchiveStreamBufferWriter.hpp" #include "SimpleFileTypeShouldCompressChecker.hpp" #include #include #include #include namespace OpenVulkano { ArchiveWriter::ArchiveWriter(const char* fileName, ArchiveConfiguration archiveConfiguration, const std::shared_ptr& logger, const char* password) : 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) { ChkErr(archive_write_add_filter(m_archive, archiveConfiguration.GetLibArchiveCompressionType())); } if (archiveConfiguration.compression != CompressionType::NONE && archiveConfiguration.compressionLevel > 0) { std::string level = "compression-level=" + std::to_string(archiveConfiguration.compressionLevel); ChkErr(archive_write_set_options(m_archive, level.c_str())); } if (password) ChkErr(archive_write_set_passphrase(m_archive, password)); ChkErr(archive_write_open_filename(m_archive, fileName)); } ArchiveWriter::~ArchiveWriter() { if (m_asBuffer) { m_asBuffer->Close(); m_asBuffer = nullptr; } ChkErr(archive_write_close(m_archive)); archive_entry_free(m_archiveEntry); } bool ArchiveWriter::AddFile(const char* fileName, const char* inArchiveName) { archive_entry_clear(m_archiveEntry); std::unique_ptr 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(), m_archiveEntry), archiveDisk.get(), m_logger); //archive_read_disk_entry_from_file(archiveDisk, m_archiveEntry, -1, nullptr); archive_entry_set_pathname(m_archiveEntry, inArchiveName); ChkErr(archive_write_header(m_archive, m_archiveEntry)); long result = LibArchiveHelper::CopyArchiveData(archiveDisk.get(), m_archive); ChkErr(result); LibArchiveHelper::CheckError(result, archiveDisk.get(), m_logger); ChkErr(archive_write_finish_entry(m_archive)); m_bytesWritten += archive_entry_size(m_archiveEntry); return true; } bool ArchiveWriter::AddFile(const FileDescription& description, const void* buffer) { WriteHeader(description); bool ok = ChkErr(archive_write_data(m_archive, buffer, description.size)); ChkErr(archive_write_finish_entry(m_archive)); return ok; } bool ArchiveWriter::AddFile(const FileDescription& description, const std::vector>& buffers) { WriteHeader(description); for(const auto& buffer : buffers) { if (buffer.first == nullptr) continue; if (!ChkErr(archive_write_data(m_archive, buffer.first, buffer.second))) { return false; } } ChkErr(archive_write_finish_entry(m_archive)); return true; } ArchiveOStream ArchiveWriter::AddFileStream(const FileDescription& description) { WriteHeader(description); return ArchiveOStream(m_asBuffer = std::make_shared(this, description.size)); } 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) { archive_entry_set_size(m_archiveEntry, fileDescription.size); } else { if (!m_archiveConfig.type.AllowsUnknownFileSize()) throw std::invalid_argument("Only ZIP files allow files of unknown size"); archive_entry_unset_size(m_archiveEntry); } archive_entry_set_filetype(m_archiveEntry, LibArchiveHelper::GetFileType(fileDescription.type)); archive_entry_set_perm(m_archiveEntry, static_cast(fileDescription.permissions)); archive_entry_set_ctime(m_archiveEntry, fileDescription.createTime, 0); archive_entry_set_mtime(m_archiveEntry, fileDescription.modTime, 0); 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: ; } } }