6#include <archive_entry.h>
24struct AddDirectoryToFileMap {
25 bool operator()(std::string_view path)
27 fileMap[std::string(path)];
33struct AddFileToFileMap {
34 bool operator()(std::string_view directoryPath, ArchiveFile &&file)
36 fileMap[std::string(directoryPath)].emplace_back(std::move(file));
43 explicit ArchiveHandle()
44 : handle(archive_read_new())
51 archive_read_free(handle);
55 ArchiveHandle(
const ArchiveHandle &) =
delete;
56 ArchiveHandle(ArchiveHandle &&) =
delete;
58 void close(std::string_view archiveName, std::string_view errorMessage)
63 if (
const auto returnCode = archive_read_free(std::exchange(handle,
nullptr)); returnCode != ARCHIVE_OK) {
64 throw ArchiveException(errorMessage.empty() ?
argsToString(
"Unable to free archive \"", archiveName,
'\"')
65 :
argsToString(
"Unable to free archive \"", archiveName,
"\" after error: ", errorMessage));
69 operator struct archive *()
74 struct archive *handle;
77void walkThroughArchiveInternal(ArchiveHandle &ar, std::string_view archiveName,
const FilePredicate &isFileRelevant,
FileHandler &&fileHandler,
81 struct archive_entry *
const entry = archive_entry_new();
82 auto fileContent = std::string();
83 while (archive_read_next_header2(ar, entry) == ARCHIVE_OK) {
85 const auto entryType(archive_entry_filetype(entry));
86 if (entryType != AE_IFDIR && entryType != AE_IFREG && entryType != AE_IFLNK) {
91 const char *filePath = archive_entry_pathname_utf8(entry);
93 filePath = archive_entry_pathname(entry);
100 const mode_t perm = archive_entry_perm(entry);
103 if (entryType == AE_IFDIR) {
104 if (!directoryHandler) {
108 const char *dirEnd = filePath;
109 for (
const char *
i = filePath; *
i; ++
i) {
114 if (directoryHandler(std::string_view(filePath,
static_cast<std::size_t
>(dirEnd - filePath)))) {
121 const char *
fileName = filePath, *dirEnd = filePath;
122 for (
const char *
i = filePath; *
i; ++
i) {
130 if (isFileRelevant && !isFileRelevant(filePath,
fileName, perm)) {
139 if (entryType == AE_IFLNK) {
140 if (fileHandler(std::string_view(filePath,
static_cast<std::string::size_type
>(dirEnd - filePath)),
148 const la_int64_t fileSize = archive_entry_size(entry);
151 fileContent.reserve(
static_cast<std::string::size_type
>(fileSize));
156 auto size = std::size_t();
157 auto offset = la_int64_t();
159 const auto returnCode = archive_read_data_block(ar,
reinterpret_cast<const void **
>(&buff), &size, &offset);
160 if (returnCode == ARCHIVE_EOF || returnCode < ARCHIVE_OK) {
163 fileContent.append(buff, size);
167 if (fileHandler(std::string_view(filePath,
static_cast<std::string::size_type
>(dirEnd - filePath)),
175 const auto *
const archiveError = archive_error_string(ar);
176 const auto errorMessage = archiveError ? std::string(archiveError) : std::string();
179 archive_entry_free(entry);
180 ar.close(archiveName, errorMessage);
195 if (archiveData.empty()) {
196 throw ArchiveException(
"Unable to open archive \"" % archiveName +
"\": archive data is empty");
199 auto ar = ArchiveHandle();
200 archive_read_support_filter_all(ar);
201 archive_read_support_format_all(ar);
202 const auto returnCode = archive_read_open_memory(ar, archiveData.data(), archiveData.size());
203 if (returnCode != ARCHIVE_OK) {
204 if (
const char *
const error = archive_error_string(ar)) {
205 throw ArchiveException(
"Unable to open/read archive \"" % archiveName %
"\": " + error);
207 throw ArchiveException(
"Unable to open/read archive \"" % archiveName +
"\": unable to open archive from memory");
210 walkThroughArchiveInternal(ar, archiveName, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
230 if (archivePath.empty()) {
233 auto ec = std::error_code();
234 auto size = std::filesystem::file_size(archivePath, ec);
236 throw ArchiveException(
"Unable to determine size of \"" % archivePath %
"\": " + ec.message());
239 throw ArchiveException(
"Unable to open archive \"" % archivePath +
"\": file is empty");
241 auto ar = ArchiveHandle();
242 archive_read_support_filter_all(ar);
243 archive_read_support_format_all(ar);
244 const auto returnCode = archive_read_open_filename(ar, archivePath.data(), 10240);
245 if (returnCode != ARCHIVE_OK) {
246 if (
const char *
const error = archive_error_string(ar)) {
247 throw ArchiveException(
"Unable to open/read archive \"" % archivePath %
"\": " + error);
249 throw ArchiveException(
"Unable to open/read archive \"" % archivePath +
"\": unable to open archive from file");
252 walkThroughArchiveInternal(ar, archivePath, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
261 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 provided 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.