Skip to content

Instantly share code, notes, and snippets.

@jackbergus
Created November 9, 2020 23:30
Show Gist options
  • Save jackbergus/14fc158488d8822067aefe2ead4779c4 to your computer and use it in GitHub Desktop.
Save jackbergus/14fc158488d8822067aefe2ead4779c4 to your computer and use it in GitHub Desktop.
Reading a .tar.xx file using a more C++ structured fashion via libarchive
cmake_minimum_required(VERSION 3.16)
project(read_archive)
set(CMAKE_CXX_STANDARD 14)
find_library(LibArchive 3.4.0)
add_executable(read_archive main.cpp)
target_link_libraries(read_archive archive)
#include <iostream>
#include <archive.h>
#include <archive_entry.h>
#include <fcntl.h>
template <size_t buffer_size = 1024>
class ReadArchiveBuffer {
char buff[buffer_size];
size_t size;
struct archive *a;
std::string path;
public:
ReadArchiveBuffer(archive *a, const std::string& path) : a(a), path(path) { size = -1; }
ReadArchiveBuffer() : ReadArchiveBuffer(nullptr, "") { size = 0; };
ReadArchiveBuffer(const ReadArchiveBuffer&) = default;
ReadArchiveBuffer& operator=(const ReadArchiveBuffer&) = default;
bool readNext(struct iovec& data) {
if (a) {
size = archive_read_data(a, buff, 1024);
}
if (size <= 0) {
data.iov_len = 0;
data.iov_base = nullptr;
return false;
} else {
data.iov_base = buff;
data.iov_len = size;
return true;
}
}
std::string filename() const { return path; }
};
template <size_t buffer_size = 1024>
class ReadArchive {
public:
ReadArchive(const std::string& file_name, size_t block_size = 10240) : ReadArchive{} {
a = archive_read_new();
archive_read_support_format_all(a);
archive_read_support_compression_all(a);
if ((r = archive_read_open_filename(a, file_name.c_str(), block_size)))
throw std::runtime_error("Cannot read file: " + file_name);
this->operator++();
}
ReadArchive() {
a = nullptr;
entry = nullptr;
r = ARCHIVE_EOF;
}
~ReadArchive() {
archive_read_close(a);
archive_read_free(a);
}
bool doStop() {
return ((r == ARCHIVE_EOF) || (r < ARCHIVE_OK) || (r < ARCHIVE_WARN) || (archive_entry_size(entry) <= 0));
}
ReadArchive& operator++() {
r = archive_read_next_header(a, &entry);
while ((r != ARCHIVE_EOF) && (r >= ARCHIVE_OK) && (r >= ARCHIVE_WARN) && (archive_entry_size(entry) == 0)) {
r = archive_read_next_header(a, &entry);
}
}
ReadArchiveBuffer<buffer_size> operator*() {
std::string filename = archive_entry_pathname(entry);
return {a, filename};
}
ReadArchiveBuffer<buffer_size> operator->() {
std::string filename = archive_entry_pathname(entry);
return {a, filename};
}
private:
struct archive *a;
struct archive_entry *entry;
int r;
};
int main() {
for (ReadArchive<> ra{"/path/to/some/file.tar.xz"}; !ra.doStop(); ++ra) {
ReadArchiveBuffer<> buff = *ra;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << buff.filename() << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
struct iovec data;
while (buff.readNext(data)) {
std::cout << std::string((const char*)data.iov_base, data.iov_len); // Printing string data
}
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment