Advertisement
dylanweber

libarchive iterator

May 10th, 2023
827
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.07 KB | None | 0 0
  1. #include <algorithm>
  2. #include <archive.h>
  3. #include <archive_entry.h>
  4. #include <filesystem>
  5. #include <iostream>
  6. #include <iterator>
  7. #include <list>
  8. #include <memory>
  9. #include <utility>
  10. #include <vector>
  11.  
  12. class File {
  13.   private:
  14.     std::string path;
  15.     std::vector<uint8_t> data;
  16.  
  17.   public:
  18.     File(struct archive *arch, struct archive_entry *arch_entry)
  19.         : path{archive_entry_pathname(arch_entry)},
  20.           data(static_cast<size_t>(archive_entry_size(arch_entry))) {
  21.         size_t ret = archive_read_data(arch, this->data.data(), this->data.size());
  22.         if (ret != this->data.size()) {
  23.             throw std::runtime_error("Could not read archive entry.");
  24.         }
  25.     }
  26.  
  27.     std::string GetPath() {
  28.         return this->path;
  29.     }
  30.  
  31.     std::vector<uint8_t> &GetData() {
  32.         return this->data;
  33.     }
  34. };
  35.  
  36. class Archive {
  37.   private:
  38.     std::filesystem::path file_path;
  39.  
  40.   public:
  41.     using unique_archive = std::unique_ptr<struct archive, decltype(&::archive_read_free)>;
  42.     using unique_archive_entry =
  43.         std::unique_ptr<struct archive_entry, decltype(&::archive_entry_free)>;
  44.  
  45.     Archive(const std::filesystem::path &path) : file_path(path) {
  46.     }
  47.  
  48.     class iterator {
  49.       private:
  50.         std::filesystem::path arch_path;
  51.         unique_archive arch;
  52.         unique_archive_entry entry;
  53.  
  54.       public:
  55.         using iterator_category = std::forward_iterator_tag;
  56.         using value_type = File;
  57.         using difference_type = void;
  58.  
  59.         iterator(const std::filesystem::path &arch_path)
  60.             : arch_path(arch_path), arch{archive_read_new(), archive_read_free},
  61.               entry{archive_entry_new(), archive_entry_free} {
  62.             int ret;
  63.  
  64.             ret = archive_read_support_filter_all(this->arch.get());
  65.             if (ret != ARCHIVE_OK) {
  66.                 throw std::runtime_error("Could not set archive filter.");
  67.             }
  68.  
  69.             ret = archive_read_support_format_all(this->arch.get());
  70.             if (ret != ARCHIVE_OK) {
  71.                 throw std::runtime_error("Could not set archive format.");
  72.             }
  73.  
  74.             ret = archive_read_open_filename_w(this->arch.get(), arch_path.wstring().c_str(), 0);
  75.             if (ret != ARCHIVE_OK) {
  76.                 throw std::runtime_error("Could not open archive.");
  77.             }
  78.  
  79.             ret = archive_read_next_header2(this->arch.get(), this->entry.get());
  80.             if (ret != ARCHIVE_OK) {
  81.                 throw std::runtime_error("Could not iterate over archive.");
  82.             }
  83.         }
  84.  
  85.         iterator(const std::filesystem::path &arch_path, struct archive *a, struct archive_entry *e)
  86.             : arch_path(arch_path), arch(a, archive_read_free), entry(e, archive_entry_free) {
  87.         }
  88.  
  89.         iterator &operator++() {
  90.             int ret = archive_read_next_header2(this->arch.get(), this->entry.get());
  91.             if (ret == ARCHIVE_EOF) {
  92.                 this->arch.reset();
  93.                 this->entry.reset();
  94.             } else if (ret != ARCHIVE_OK) {
  95.                 throw std::runtime_error("Could not iterate over archive.");
  96.             }
  97.  
  98.             return *this;
  99.         }
  100.  
  101.         File operator*() const {
  102.             return File{this->arch.get(), this->entry.get()};
  103.         }
  104.  
  105.         friend bool operator==(const iterator &a, const iterator &b) {
  106.             if (a.entry.get() == nullptr && b.entry.get() == nullptr) {
  107.                 return a.arch_path == b.arch_path;
  108.             } else if (a.entry.get() == nullptr || b.entry.get() == nullptr) {
  109.                 return false;
  110.             }
  111.  
  112.             std::string a_path{archive_entry_pathname(a.entry.get())},
  113.                 b_path{archive_entry_pathname(b.entry.get())};
  114.             return a_path == b_path && a.arch_path == b.arch_path;
  115.         }
  116.  
  117.         friend bool operator!=(const iterator &a, const iterator &b) {
  118.             if (a.entry.get() == nullptr && b.entry.get() == nullptr) {
  119.                 return a.arch_path != b.arch_path;
  120.             } else if (a.entry.get() == nullptr || b.entry.get() == nullptr) {
  121.                 return true;
  122.             }
  123.  
  124.             std::string a_path{archive_entry_pathname(a.entry.get())},
  125.                 b_path{archive_entry_pathname(b.entry.get())};
  126.             return a_path != b_path || a.arch_path != b.arch_path;
  127.         }
  128.     };
  129.  
  130.     iterator begin() {
  131.         return iterator{this->file_path};
  132.     }
  133.  
  134.     iterator end() {
  135.         return iterator{this->file_path, nullptr, nullptr};
  136.     }
  137. };
  138.  
  139. int main() {
  140.     // std::unique_ptr<struct archive, decltype(&::archive_read_free)> a{archive_read_new(),
  141.     //                                                                archive_read_free};
  142.     // int r;
  143.  
  144.     // archive_read_support_filter_all(a.get());
  145.     // archive_read_support_format_all(a.get());
  146.     // r = archive_read_open_filename(a.get(), "archive.tar", 10240);   // Note 1
  147.     // if (r != ARCHIVE_OK)
  148.     //  return EXIT_FAILURE;
  149.  
  150.     // std::unique_ptr<struct archive_entry, decltype(&::archive_entry_free)> entry{
  151.     //  archive_entry_new2(a.get()), archive_entry_free},
  152.     //  entry2{archive_entry_new2(a.get()), archive_entry_free};
  153.     // while (archive_read_next_header2(a.get(), entry.get()) == ARCHIVE_OK &&
  154.     //     archive_read_next_header2(a.get(), entry2.get()) == ARCHIVE_OK) {
  155.     //  printf("%s\n", archive_entry_pathname(entry.get()));
  156.     //  printf("%s\n", archive_entry_pathname(entry2.get()));
  157.     //  archive_read_data_skip(a.get());  // Note 2
  158.     // }
  159.  
  160.     Archive arch{"archive.tar"};
  161.     for (File f : arch) {
  162.         for (File g : arch) {
  163.             std::cout << g.GetPath() << std::endl;
  164.         }
  165.         std::cout << f.GetPath() << std::endl;
  166.         std::cout << "Size: " << f.GetData().size() << std::endl;
  167.         std::cout << std::string{f.GetData().begin(), f.GetData().end()} << std::endl;
  168.     }
  169.  
  170.     return EXIT_SUCCESS;
  171. }
  172.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement