This commit is contained in:
parent
40fb299350
commit
d33d0ba544
6 changed files with 187 additions and 35 deletions
|
@ -8,7 +8,6 @@ steps:
|
||||||
commands:
|
commands:
|
||||||
- meson build
|
- meson build
|
||||||
- ninja -C build
|
- ninja -C build
|
||||||
- build/src/xwim ../compile-commands.json
|
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
project('xwim', 'cpp', default_options : ['cpp_std=c++17'])
|
project('xwim', 'cpp', default_options : ['cpp_std=c++17'])
|
||||||
subdir('src')
|
subdir('src')
|
||||||
|
|
123
src/archive.cpp
123
src/archive.cpp
|
@ -1,26 +1,125 @@
|
||||||
#include "archive.hpp"
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
namespace logger = spdlog;
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <archive_entry.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "archive.hpp"
|
||||||
#include "spec.hpp"
|
#include "spec.hpp"
|
||||||
|
|
||||||
namespace xwim {
|
namespace xwim {
|
||||||
Archive::Archive(std::string path) : path{std::filesystem::path(path)} {}
|
|
||||||
Archive::Archive(std::filesystem::path&& path) : path{path} {}
|
|
||||||
|
|
||||||
ArchiveSpec Archive::check() {
|
Archive::Archive(std::string path) : path{std::filesystem::path(path)} {
|
||||||
return ArchiveSpec{.is_root_dir = true,
|
int r; // libarchive error handling
|
||||||
.is_root_dir_filename = true,
|
|
||||||
.has_subarchive = false};
|
logger::trace("Setting up archive reader");
|
||||||
|
this->xwim_archive = archive_read_new();
|
||||||
|
archive_read_support_filter_all(this->xwim_archive);
|
||||||
|
archive_read_support_format_all(this->xwim_archive);
|
||||||
|
|
||||||
|
logger::trace("Reading archive at {}", path.c_str());
|
||||||
|
r = archive_read_open_filename(this->xwim_archive, path.c_str(), 10240);
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
throw ArchiveException{"Could not open archive file", this->xwim_archive};
|
||||||
|
|
||||||
|
logger::trace("Archive read succesfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Archive::extract(ExtractSpec extract_spec) {
|
Archive::~Archive() {
|
||||||
std::cout << "Make dir:" << extract_spec.make_dir
|
archive_read_free(this->xwim_archive);
|
||||||
<< "Dirname: " << extract_spec.dirname
|
}
|
||||||
<< "Archname: " << this->path
|
|
||||||
<< std::endl;
|
static archive_entry* _archive_next_entry(archive* archive) {
|
||||||
|
int r; // libarchive error handling
|
||||||
|
archive_entry* entry;
|
||||||
|
logger::trace("Listing next archive entry");
|
||||||
|
r = archive_read_next_header(archive, &entry);
|
||||||
|
if (r != ARCHIVE_OK)
|
||||||
|
throw(ArchiveException{"Could not list archive", archive});
|
||||||
|
|
||||||
|
logger::trace("Got archive header");
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
static void _spec_is_root_filename(ArchiveSpec* spec,
|
||||||
|
archive_entry* entry,
|
||||||
|
std::filesystem::path* filepath) {
|
||||||
|
std::filesystem::path entry_path{archive_entry_pathname(entry)};
|
||||||
|
std::filesystem::path norm_stem = filepath->filename();
|
||||||
|
|
||||||
|
while (norm_stem.has_extension())
|
||||||
|
norm_stem = norm_stem.stem();
|
||||||
|
|
||||||
|
if (*entry_path.begin() != norm_stem) {
|
||||||
|
logger::debug("Archive root does not match archive name");
|
||||||
|
spec->is_root_filename = false;
|
||||||
|
} else {
|
||||||
|
logger::debug("Archive root matches archive name");
|
||||||
|
spec->is_root_filename = true;
|
||||||
|
}
|
||||||
|
logger::debug("\t-> Archive root: {}", entry_path.begin()->string());
|
||||||
|
logger::debug("\t-> Archive stem: {}", norm_stem.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spec_is_root_dir(ArchiveSpec* spec, archive_entry* entry) {
|
||||||
|
if (S_ISDIR(archive_entry_filetype(entry))) {
|
||||||
|
logger::debug("Archive root is directory");
|
||||||
|
spec->is_root_dir = true;
|
||||||
|
} else {
|
||||||
|
logger::debug("Archive root is not a directory");
|
||||||
|
spec->is_root_dir = false;
|
||||||
|
}
|
||||||
|
logger::debug("\t-> Archive mode_t: {0:o}", archive_entry_filetype(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spec_has_single_root(ArchiveSpec* spec,
|
||||||
|
archive_entry* first_entry,
|
||||||
|
archive* archive) {
|
||||||
|
|
||||||
|
std::filesystem::path first_entry_root = *(std::filesystem::path{archive_entry_pathname(first_entry)}.begin());
|
||||||
|
logger::trace("Testing roots");
|
||||||
|
|
||||||
|
spec->has_single_root = true;
|
||||||
|
archive_entry* entry;
|
||||||
|
while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
|
||||||
|
std::filesystem::path next_entry{archive_entry_pathname(entry)};
|
||||||
|
logger::trace("Path: {}, Root: {}", next_entry.string(), next_entry.begin()->string());
|
||||||
|
|
||||||
|
if (first_entry_root != *next_entry.begin()) {
|
||||||
|
logger::debug("Archive has multiple roots");
|
||||||
|
logger::debug("\t-> Archive root I: {}", first_entry_root.begin()->string());
|
||||||
|
logger::debug("\t-> Archive root II: {}", next_entry.begin()->string());
|
||||||
|
|
||||||
|
spec->has_single_root = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spec->has_single_root)
|
||||||
|
logger::debug("Archive has single root: {}", first_entry_root.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiveSpec Archive::check() {
|
||||||
|
logger::trace("Creating archive spec for {}", this->path.string());
|
||||||
|
|
||||||
|
ArchiveSpec archive_spec;
|
||||||
|
|
||||||
|
archive_entry* first_entry = _archive_next_entry(this->xwim_archive);
|
||||||
|
if (first_entry == nullptr) { // archive is empty
|
||||||
|
logger::debug("Archive is empty");
|
||||||
|
return {false, false, false};
|
||||||
|
}
|
||||||
|
logger::trace("Found archive entry {}", archive_entry_pathname(first_entry));
|
||||||
|
|
||||||
|
_spec_is_root_filename(&archive_spec, first_entry, &this->path);
|
||||||
|
_spec_is_root_dir(&archive_spec, first_entry);
|
||||||
|
_spec_has_single_root(&archive_spec, first_entry, this->xwim_archive);
|
||||||
|
|
||||||
|
return archive_spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace xwim
|
} // namespace xwim
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#ifndef ARCHIVE_H
|
#ifndef ARCHIVE_H
|
||||||
#define ARCHIVE_H
|
#define ARCHIVE_H
|
||||||
|
|
||||||
|
#include <archive.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include "spec.hpp"
|
#include "spec.hpp"
|
||||||
|
|
||||||
|
@ -11,15 +16,33 @@ namespace xwim {
|
||||||
class Archive {
|
class Archive {
|
||||||
private:
|
private:
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
|
archive* xwim_archive;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Archive(std::string path);
|
explicit Archive(std::string path);
|
||||||
explicit Archive(std::filesystem::path&& path);
|
~Archive();
|
||||||
|
|
||||||
ArchiveSpec check();
|
ArchiveSpec check();
|
||||||
void extract(ExtractSpec normalize_spec);
|
void extract(ExtractSpec normalize_spec);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ArchiveException : public std::exception {
|
||||||
|
private:
|
||||||
|
std::string _what;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ArchiveException(std::string what, archive* archive) {
|
||||||
|
if (archive_error_string(archive)) {
|
||||||
|
_what = fmt::format("{}: {}", what, archive_error_string(archive));
|
||||||
|
} else {
|
||||||
|
_what = fmt::format("{}", what);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* what() const noexcept
|
||||||
|
{ return this->_what.c_str(); }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xwim
|
} // namespace xwim
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
22
src/main.cpp
22
src/main.cpp
|
@ -1,3 +1,7 @@
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
namespace logger = spdlog;
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -6,15 +10,17 @@
|
||||||
#include "spec.hpp"
|
#include "spec.hpp"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
std::string filename {argv[1]};
|
logger::set_level(logger::level::trace);
|
||||||
xwim::Archive archive {filename};
|
logger::flush_on(logger::level::trace);
|
||||||
|
|
||||||
xwim::ArchiveSpec asp = archive.check();
|
try {
|
||||||
|
std::string filename{argv[1]};
|
||||||
|
xwim::Archive archive{filename};
|
||||||
|
xwim::ArchiveSpec spec = archive.check();
|
||||||
|
|
||||||
std::cout << "Has subarch: " << asp.has_subarchive
|
logger::info("{}", spec);
|
||||||
<< "Is root: " << asp.is_root_dir
|
|
||||||
<< "Is root dir filename: " << asp.is_root_dir_filename
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
archive.extract(xwim::ExtractSpec {.make_dir=true, .dirname="Test"});
|
} catch (xwim::ArchiveException& ae) {
|
||||||
|
logger::error("{}", ae.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
49
src/spec.hpp
49
src/spec.hpp
|
@ -1,18 +1,43 @@
|
||||||
#ifndef SPEC_H
|
#ifndef SPEC_H
|
||||||
#define SPEC_H
|
#define SPEC_H
|
||||||
|
|
||||||
#include <filesystem>
|
#include <archive.h>
|
||||||
namespace xwim {
|
#include <fmt/core.h>
|
||||||
struct ArchiveSpec {
|
|
||||||
bool is_root_dir;
|
|
||||||
bool is_root_dir_filename;
|
|
||||||
bool has_subarchive;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ExtractSpec {
|
#include <filesystem>
|
||||||
bool make_dir;
|
#include <memory>
|
||||||
std::filesystem::path dirname;
|
|
||||||
};
|
namespace xwim {
|
||||||
}
|
|
||||||
|
struct ArchiveSpec {
|
||||||
|
bool has_single_root = false;
|
||||||
|
bool is_root_filename = false;
|
||||||
|
bool is_root_dir = false;
|
||||||
|
bool has_subarchive = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ExtractSpec {
|
||||||
|
bool make_dir;
|
||||||
|
std::filesystem::path dirname;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xwim
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct fmt::formatter<xwim::ArchiveSpec> {
|
||||||
|
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const xwim::ArchiveSpec& spec, FormatContext& ctx) {
|
||||||
|
return format_to(ctx.out(),"Archive["
|
||||||
|
" .has_single_root={},"
|
||||||
|
" .is_root_filename={}"
|
||||||
|
" .is_root_dir={}"
|
||||||
|
" .has_subarchive={}"
|
||||||
|
" ]",
|
||||||
|
spec.has_single_root, spec.is_root_filename,
|
||||||
|
spec.is_root_dir, spec.has_subarchive);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue