Advertisement
Guest User

archive.cc

a guest
May 14th, 2022
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.36 KB | None | 0 0
  1. #include <algorithm>
  2. #include <utility>
  3. #include <stdexcept>
  4. #include <filesystem>
  5.  
  6. #include "archive.hh"
  7. #include "fileutils.hh"
  8.  
  9. using namespace std;
  10.  
  11. Archive::Archive(string path)
  12.   : m_path(move(path))
  13. {
  14.   m_file = fstream(m_path, ios_base::binary | ios_base::in | ios_base::out);
  15.   m_file.seekg(0, ios_base::end);
  16.   if(m_file.tellg() == 0)
  17.     addFolder(0);
  18.   else
  19.     loadFolders();
  20. }
  21.  
  22. uint16_t Archive::addFolder(uint16_t parentIndex)
  23. {
  24.   int i = 0;
  25.   while(i < m_folders.size() && !m_folders[i].m_deleted)
  26.     ++i;
  27.  
  28.   if(i < m_folders.size())
  29.     m_folders[i].m_deleted = false;
  30.   else
  31.     m_folders.emplace_back(this, i);
  32.  
  33.   m_folders[i].m_parentIndex = parentIndex;
  34.   m_folders[i].m_created = true;
  35.   return i;
  36. }
  37.  
  38. void Archive::removeFolder(uint16_t index)
  39. {
  40.   auto &folder = m_folders[index];
  41.   if(!folder.m_created)
  42.     m_deletedFolders.push_back(exchange(folder, Folder(this, index)));
  43.   else
  44.     folder = Folder(this, index);
  45.   folder.m_deleted = true;
  46. }
  47.  
  48. void Archive::loadFolders()
  49. {
  50.   m_file.seekg(-10, ios_base::end);
  51.  
  52.   auto numFolders = readNumber<uint16_t>(m_file);
  53.   m_endDataOffset = readNumber<uint64_t>(m_file);
  54.  
  55.   m_file.seekg(-10 - numFolders*4, ios_base::end);
  56.  
  57.   auto folderOffsets = vector<int32_t>(numFolders);
  58.   for(auto &offset : folderOffsets)
  59.     offset = readNumber<int32_t>(m_file);
  60.  
  61.   m_folders.reserve(numFolders);
  62.   for(int i = 0; i < folderOffsets.size(); ++i)
  63.   {
  64.     m_folders.emplace_back(this, i);
  65.     auto &folder = m_folders.back();
  66.     m_file.seekg(folderOffsets[i], ios_base::end);
  67.     folder.read();
  68.   }
  69.  
  70.   setSynced(true);
  71. }
  72.  
  73. FolderHandle Archive::getRootFolder()
  74. {
  75.   return FolderHandle(this, 0);
  76. }
  77.  
  78. void Archive::sync()
  79. {
  80.   if(!m_synced)
  81.   {
  82.     syncRemoveFiles();
  83.     syncAddFiles();
  84.     syncFolders();
  85.     syncSize();
  86.     setSynced(true);
  87.   }
  88. }
  89.  
  90. void Archive::syncRemoveFiles()
  91. {
  92.   vector<pair<uint64_t,uint64_t>> skippedIntervals;
  93.  
  94.   auto collectDeleted = [&](Folder &folder)
  95.   {
  96.     if(!folder.m_synced)
  97.       for(auto &entry : folder.m_entries)
  98.         if(entry.type == Folder::Entry::Type::File && entry.deleted)
  99.           skippedIntervals.emplace_back(entry.offset, entry.offset + entry.size);
  100.   };
  101.  
  102.   for(auto &folder : m_folders)
  103.     if(!folder.m_deleted && !folder.m_created)
  104.       collectDeleted(folder);
  105.  
  106.   for(auto &folder : m_deletedFolders)
  107.     collectDeleted(folder);
  108.  
  109.   if(!skippedIntervals.empty())
  110.   {
  111.     sort(skippedIntervals.begin(), skippedIntervals.end(),
  112.          [](auto interval1, auto interval2){return interval1.first < interval2.first;});
  113.     skippedIntervals.emplace_back(m_endDataOffset, m_endDataOffset);
  114.     auto numIntervals = skippedIntervals.size();
  115.  
  116.     auto oldFile = fstream(m_path, ios_base::binary | ios_base::in);
  117.     m_file.seekp(skippedIntervals[0].first);
  118.  
  119.     for(int i = 1; i < numIntervals; ++i)
  120.     {
  121.       auto prevSkipTo = skippedIntervals[i-1].second;
  122.       auto nextSkipFrom = skippedIntervals[i].first;
  123.  
  124.       oldFile.seekg(prevSkipTo);
  125.       copyFile(oldFile, m_file, nextSkipFrom - prevSkipTo);
  126.     }
  127.  
  128.     auto intervalSums = vector<uint64_t>(numIntervals, 0);
  129.     for(int i = 1; i < numIntervals; ++i)
  130.       intervalSums[i] = intervalSums[i-1] + skippedIntervals[i].second - skippedIntervals[i].first;
  131.  
  132.     for(auto &folder : m_folders)
  133.       if(!folder.m_deleted && !folder.m_created)
  134.         for(auto &entry : folder.m_entries)
  135.           if(entry.type == Folder::Entry::Type::File && !entry.deleted && !entry.created)
  136.           {
  137.             auto nextIntervalIndex = upper_bound(skippedIntervals.begin(), skippedIntervals.end(), entry.offset,
  138.                                                  [](auto offset, auto interval){return offset < interval.second;})
  139.                                      - skippedIntervals.begin();
  140.             entry.offset -= intervalSums[nextIntervalIndex-1];
  141.           }
  142.  
  143.     m_endDataOffset = m_file.tellp();
  144.   }
  145. }
  146.  
  147. void Archive::syncAddFiles()
  148. {
  149.   for(auto &folder : m_folders)
  150.     if(!folder.m_deleted && !folder.m_synced)
  151.       for(auto &entry : folder.m_entries)
  152.         if(entry.type == Folder::Entry::Type::File && entry.created)
  153.         {
  154.           auto externalFile = fstream(entry.externalPath, ios_base::binary | ios_base::in);
  155.           entry.offset = m_file.tellp();
  156.           entry.size = copyFile(externalFile, m_file);
  157.         }
  158.  
  159.   m_endDataOffset = m_file.tellp();
  160. }
  161.  
  162. void Archive::syncFolders()
  163. {
  164.   while(m_folders.back().m_deleted)
  165.     m_folders.pop_back();
  166.  
  167.   auto folderIndexRemap = vector<uint16_t>(m_folders.size());
  168.   for(int i = 0; i < m_folders.size(); ++i)
  169.   {
  170.     if(m_folders[i].m_deleted)
  171.     {
  172.       m_folders[i] = move(m_folders.back());
  173.       m_folders.pop_back();
  174.       folderIndexRemap[m_folders.size()] = i;
  175.  
  176.       while(m_folders.back().m_deleted)
  177.         m_folders.pop_back();
  178.     }
  179.     else
  180.     {
  181.       folderIndexRemap[i] = i;
  182.     }
  183.   }
  184.  
  185.   auto numFolders = uint16_t(m_folders.size());
  186.   auto folderOffsets = vector<int32_t>(numFolders);
  187.   auto foldersSegmentOffset = m_file.tellp();
  188.  
  189.   for(int i = 0; i < numFolders; ++i)
  190.   {
  191.     auto &folder = m_folders[i];
  192.     folder.m_selfIndex = i;
  193.     folder.m_parentIndex = folderIndexRemap[folder.m_parentIndex];
  194.     for(auto it = folder.m_entries.begin();
  195.         it != folder.m_entries.end();)
  196.     {
  197.       if(it->deleted)
  198.       {
  199.         it = folder.m_entries.erase(it);
  200.       }
  201.       else
  202.       {
  203.         if(it->type == Folder::Entry::Type::Folder)
  204.           it->offset = folderIndexRemap[it->offset];
  205.         ++it;
  206.       }
  207.     }
  208.  
  209.     folderOffsets[i] = int32_t(int64_t(m_file.tellp()) - int64_t(foldersSegmentOffset));
  210.     folder.write();
  211.   }
  212.  
  213.   auto foldersSegmentLength = m_file.tellp() - foldersSegmentOffset;
  214.  
  215.   for(auto &offset : folderOffsets)
  216.   {
  217.     auto off = int32_t(offset - foldersSegmentLength - numFolders*4 - 10);
  218.     writeNumber(m_file, off);
  219.   }
  220.  
  221.   writeNumber(m_file, numFolders);
  222.   writeNumber(m_file, m_endDataOffset);
  223. }
  224.  
  225. void Archive::syncSize()
  226. {
  227.   auto newSize = m_file.tellp();
  228.   m_file.close();
  229.   filesystem::resize_file(m_path, newSize);
  230.   m_file.open(m_path, ios_base::binary | ios_base::in | ios_base::out);
  231. }
  232.  
  233. void Archive::setSynced(bool synced)
  234. {
  235.   if((m_synced = synced))
  236.     for(auto &folder : m_folders)
  237.       folder.setSynced(true);
  238. }
  239.  
  240. Folder::Folder(Archive *archive, uint16_t selfIndex)
  241.   : m_archive(archive)
  242.   , m_selfIndex(selfIndex)
  243. {
  244. }
  245.  
  246. FolderHandle Folder::getChildFolder(Entry &entry)
  247. {
  248.   if(entry.type != Entry::Type::Folder)
  249.     throw runtime_error("Folder::getChildFolder: Not a folder!");
  250.  
  251.   return FolderHandle(m_archive, entry.offset);
  252. }
  253.  
  254. FolderHandle Folder::getParentFolder()
  255. {
  256.   return FolderHandle(m_archive, m_parentIndex);
  257. }
  258.  
  259. void Folder::addFolder(std::string name)
  260. {
  261.   auto archive = m_archive;
  262.   auto selfIndex = m_selfIndex;
  263.  
  264.   Entry entry;
  265.   entry.type = Entry::Type::Folder;
  266.   entry.name = move(name);
  267.   entry.offset = archive->addFolder(selfIndex);
  268.   entry.created = true;
  269.  
  270.   auto &self = archive->m_folders[selfIndex];
  271.   self.m_entries.push_back(move(entry));
  272.   self.setSynced(false);
  273. }
  274.  
  275. void Folder::addFile(std::string name, std::string externalPath)
  276. {
  277.   Entry entry;
  278.   entry.type = Entry::Type::File;
  279.   entry.name = move(name);
  280.   entry.externalPath = move(externalPath);
  281.   entry.created = true;
  282.   m_entries.push_back(move(entry));
  283.   setSynced(false);
  284. }
  285.  
  286. void Folder::extract(Entry &entry, std::string path)
  287. {
  288.   if(entry.type != Entry::Type::File)
  289.     throw runtime_error("Folder::extract: Not a file!");
  290.  
  291.   if(entry.created)
  292.     throw runtime_error("Folder::extract: Not added to archive yet!");
  293.  
  294.   m_archive->m_file.seekg(entry.offset);
  295.   auto file = ofstream(path);
  296.   copyFile(m_archive->m_file, file, entry.size);
  297. }
  298.  
  299. void Folder::remove(Entry &entry)
  300. {
  301.   remove(&entry - &m_entries[0]);
  302. }
  303.  
  304. void Folder::remove(uint16_t index)
  305. {
  306.   auto &entry = m_entries[index];
  307.  
  308.   if(entry.type == Entry::Type::Folder)
  309.   {
  310.     auto &childFolder = m_archive->m_folders[entry.offset];
  311.     for(int i = childFolder.m_entries.size() - 1; i >= 0; --i)
  312.       childFolder.remove(i);
  313.  
  314.     m_archive->removeFolder(entry.offset);
  315.   }
  316.  
  317.   if(entry.created)
  318.     m_entries.erase(m_entries.begin() + index);
  319.   else
  320.     entry.deleted = true;
  321.  
  322.   setSynced(false);
  323. }
  324.  
  325. void Folder::read()
  326. {
  327.   m_parentIndex = readNumber<uint16_t>(m_archive->m_file);
  328.   auto numEntries = readNumber<uint16_t>(m_archive->m_file);
  329.   m_entries = vector<Entry>(numEntries);
  330.   for(auto &entry : m_entries)
  331.     entry.read(m_archive->m_file);
  332. }
  333.  
  334. void Folder::write()
  335. {
  336.   writeNumber(m_archive->m_file, m_parentIndex);
  337.   writeNumber(m_archive->m_file, uint16_t(m_entries.size()));
  338.   for(auto &entry : m_entries)
  339.     entry.write(m_archive->m_file);
  340. }
  341.  
  342. void Folder::setSynced(bool synced)
  343. {
  344.   if(!(m_synced = synced))
  345.     m_archive->setSynced(false);
  346. }
  347.  
  348. void Folder::Entry::read(istream &in)
  349. {
  350.   type = Type(readNumber<uint8_t>(in));
  351.   if(type == Type::File)
  352.   {
  353.     offset = readNumber<uint64_t>(in);
  354.     size = readNumber<uint64_t>(in);
  355.   }
  356.   else
  357.   {
  358.     offset = readNumber<uint32_t>(in);
  359.   }
  360.   name = readString(in);
  361. }
  362.  
  363. void Folder::Entry::write(ostream &out)
  364. {
  365.   writeNumber(out, uint8_t(type));
  366.   if(type == Type::File)
  367.   {
  368.     writeNumber(out, offset);
  369.     writeNumber(out, size);
  370.   }
  371.   else
  372.   {
  373.     writeNumber(out, uint32_t(offset));
  374.   }
  375.   writeString(out, name);
  376. }
  377.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement