7#include <archive_entry.h>
25struct AddDirectoryToFileMap {
26 bool operator()(std::string_view path)
28 fileMap[std::string(path)];
34struct AddFileToFileMap {
35 bool operator()(std::string_view directoryPath,
ArchiveFile &&file)
37 fileMap[std::string(directoryPath)].emplace_back(std::move(file));
44 explicit ArchiveHandle()
45 : handle(archive_read_new())
52 archive_read_free(handle);
56 ArchiveHandle(
const ArchiveHandle &) =
delete;
57 ArchiveHandle(ArchiveHandle &&) =
delete;
59 void close(std::string_view archiveName, std::string_view errorMessage)
64 if (
const auto returnCode = archive_read_free(std::exchange(handle,
nullptr)); returnCode != ARCHIVE_OK) {
66 :
argsToString(
"Unable to free archive \"", archiveName,
"\" after error: ", errorMessage));
70 operator struct archive *()
75 struct archive *handle;
78void walkThroughArchiveInternal(ArchiveHandle &ar, std::string_view archiveName,
const FilePredicate &isFileRelevant,
FileHandler &&fileHandler,
82 struct archive_entry *
const entry = archive_entry_new();
83 auto fileContent = std::string();
84 while (archive_read_next_header2(ar, entry) == ARCHIVE_OK) {
86 const auto entryType(archive_entry_filetype(entry));
87 if (entryType != AE_IFDIR && entryType != AE_IFREG && entryType != AE_IFLNK) {
92 const char *filePath = archive_entry_pathname_utf8(entry);
94 filePath = archive_entry_pathname(entry);
101 const mode_t perm = archive_entry_perm(entry);
104 if (entryType == AE_IFDIR) {
105 if (!directoryHandler) {
109 const char *dirEnd = filePath;
110 for (
const char *
i = filePath; *
i; ++
i) {
115 if (directoryHandler(std::string_view(filePath,
static_cast<std::size_t
>(dirEnd - filePath)))) {
122 const char *
fileName = filePath, *dirEnd = filePath;
123 for (
const char *
i = filePath; *
i; ++
i) {
131 if (isFileRelevant && !isFileRelevant(filePath,
fileName, perm)) {
140 if (entryType == AE_IFLNK) {
141 if (fileHandler(std::string_view(filePath,
static_cast<std::string::size_type
>(dirEnd - filePath)),
149 const la_int64_t fileSize = archive_entry_size(entry);
152 fileContent.reserve(
static_cast<std::string::size_type
>(fileSize));
157 auto size = std::size_t();
158 auto offset = la_int64_t();
160 const auto returnCode = archive_read_data_block(ar,
reinterpret_cast<const void **
>(&buff), &size, &offset);
161 if (returnCode == ARCHIVE_EOF || returnCode < ARCHIVE_OK) {
164 fileContent.append(buff, size);
168 if (fileHandler(std::string_view(filePath,
static_cast<std::string::size_type
>(dirEnd - filePath)),
176 const auto *
const archiveError = archive_error_string(ar);
177 const auto errorMessage = archiveError ? std::string(archiveError) :
std::string();
180 archive_entry_free(entry);
181 ar.close(archiveName, errorMessage);
196 if (archiveData.empty()) {
197 throw ArchiveException(
"Unable to open archive \"" % archiveName +
"\": archive data is empty");
200 auto ar = ArchiveHandle();
201 archive_read_support_filter_all(ar);
202 archive_read_support_format_all(ar);
203 const auto returnCode = archive_read_open_memory(ar, archiveData.data(), archiveData.size());
204 if (returnCode != ARCHIVE_OK) {
205 if (
const char *
const error = archive_error_string(ar)) {
206 throw ArchiveException(
"Unable to open/read archive \"" % archiveName %
"\": " + error);
208 throw ArchiveException(
"Unable to open/read archive \"" % archiveName +
"\": unable to open archive from memory");
211 walkThroughArchiveInternal(ar, archiveName, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
231 if (archivePath.empty()) {
234 auto ec = std::error_code();
235 auto size = std::filesystem::file_size(archivePath, ec);
237 throw ArchiveException(
"Unable to determine size of \"" % archivePath %
"\": " + ec.message());
240 throw ArchiveException(
"Unable to open archive \"" % archivePath +
"\": file is empty");
242 auto ar = ArchiveHandle();
243 archive_read_support_filter_all(ar);
244 archive_read_support_format_all(ar);
245 const auto returnCode = archive_read_open_filename(ar, archivePath.data(), 10240);
246 if (returnCode != ARCHIVE_OK) {
247 if (
const char *
const error = archive_error_string(ar)) {
248 throw ArchiveException(
"Unable to open/read archive \"" % archivePath %
"\": " + error);
250 throw ArchiveException(
"Unable to open/read archive \"" % archivePath +
"\": unable to open archive from file");
253 walkThroughArchiveInternal(ar, archivePath, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
262 walkThroughArchive(archivePath, isFileRelevant, AddFileToFileMap{ results }, AddDirectoryToFileMap{ results });
The ArchiveException class is thrown by the various archiving-related functions of this library when ...
~ArchiveException() override
Destroys the ArchiveException.
static constexpr DateTime fromTimeStampGmt(std::time_t timeStamp)
Constructs a new DateTime object with the GMT time from the specified UNIX timeStamp.
Contains all utilities provides by the c++utilities library.
CPP_UTILITIES_EXPORT void walkThroughArchiveFromBuffer(std::string_view archiveData, std::string_view archiveName, const FilePredicate &isFileRelevant=FilePredicate(), FileHandler &&fileHandler=FileHandler(), DirectoryHandler &&directoryHandler=DirectoryHandler())
Invokes callbacks for files and directories in the specified archive.
CPP_UTILITIES_EXPORT FileMap extractFilesFromBuffer(std::string_view archiveData, std::string_view archiveName, const FilePredicate &isFileRelevant=FilePredicate())
Extracts the specified archive.
CPP_UTILITIES_EXPORT void walkThroughArchive(std::string_view archivePath, const FilePredicate &isFileRelevant=FilePredicate(), FileHandler &&fileHandler=FileHandler(), DirectoryHandler &&directoryHandler=DirectoryHandler())
Invokes callbacks for files and directories in the specified archive.
std::function< bool(const char *, const char *, mode_t)> FilePredicate
A function that is invoked for each file within an archive. If it returns true, the file is considere...
CPP_UTILITIES_EXPORT FileMap extractFiles(std::string_view archivePath, const FilePredicate &isFileRelevant=FilePredicate())
Extracts the specified archive.
std::function< bool(std::string_view path)> DirectoryHandler
A function that is invoked by the walk-through-functions to return a directory.
std::map< std::string, std::vector< ArchiveFile > > FileMap
A map of files extracted from an archive. Keys represent directories and values files within those di...
StringType argsToString(Args &&...args)
std::function< bool(std::string_view path, ArchiveFile &&file)> FileHandler
A function that is invoked by the walk-through-functions to return a file.
CPP_UTILITIES_EXPORT std::string fileName(const std::string &path)
Returns the file name and extension of the specified path string.
The ArchiveFile class holds data about a file within an archive.