From a1bb81360e7f1964498de82dfc0c3f6ff3037182 Mon Sep 17 00:00:00 2001 From: Aki Date: Tue, 9 Aug 2022 23:52:11 +0200 Subject: Added methods to inspect blocks in the archive This actually yields predicted tendency to leave a single unused block at the start of the archive in case where directory starts to need more blocks and none of new files can fill it in. Interestingly it also shows a long sequence of unused blocks just before the directory that is right at the end of the archive. The cause for that can be pointed out in original implementation of FindDataBlocks method. --- ArchiveEx/Archive.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ ArchiveEx/Archive.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/ArchiveEx/Archive.cpp b/ArchiveEx/Archive.cpp index 134404c..8ca7b71 100644 --- a/ArchiveEx/Archive.cpp +++ b/ArchiveEx/Archive.cpp @@ -23,6 +23,8 @@ static inline std::size_t ConvertPathSeparator(const char* src, char* dest); static constexpr std::uint32_t VERSION {0x0010}; static constexpr std::size_t BLOCK_SIZE {1024}; static constexpr std::size_t DIRECTORY_MARGIN {64}; +static constexpr int UNUSED_BLOCK {-1}; +static constexpr int DIRECTORY_BLOCK {-2}; Archive::Archive(const char* p) : @@ -56,6 +58,7 @@ Archive::Archive(const char* p) : header.directory.compressed_size); if (Z_OK != err) throw "could not uncompress directory"; + UpdateBlockMap(); } @@ -111,6 +114,29 @@ Archive::Find(const char* filepath) const void +Archive::UpdateBlockMap() +{ + const std::size_t last_directory_block = header.directory.offset / BLOCK_SIZE + DirectoryBlocks() - 1; + std::size_t last_block = last_directory_block; + for (const auto& entry : entries) { + const std::size_t block = entry.offset / BLOCK_SIZE + BytesToBlocks(entry.compressed_size) - 1; + if (last_block < block) + last_block = block; + } + blocks.clear(); + blocks.resize(last_block + 1, UNUSED_BLOCK); + for (std::size_t n = header.directory.offset / BLOCK_SIZE; n <= last_directory_block; ++n) + blocks[n] = DIRECTORY_BLOCK; + for (std::size_t i = 0; i < entries.size(); ++i) { + const std::size_t from = entries[i].offset / BLOCK_SIZE; + const std::size_t exclusive_to = from + BytesToBlocks(entries[i].compressed_size); + for (std::size_t n = from; n < exclusive_to; ++n) + blocks[n] = i; + } +} + + +void Archive::PrintNamesOfEntries() const { for (const auto& entry : entries) @@ -118,6 +144,25 @@ Archive::PrintNamesOfEntries() const } +void +Archive::PrintBlocks() const +{ + for (std::size_t i = 0; i < blocks.size(); ++i) { + std::printf("%ld\t", i); + switch (blocks[i]) { + case UNUSED_BLOCK: + std::printf("(unused)\n"); + break; + case DIRECTORY_BLOCK: + std::printf("(dir)\n"); + break; + default: + std::printf("%s\n", entries[blocks[i]].name); + } + } +} + + std::size_t Archive::DirectoryBlocks() const { diff --git a/ArchiveEx/Archive.h b/ArchiveEx/Archive.h index cbaf571..e19c718 100644 --- a/ArchiveEx/Archive.h +++ b/ArchiveEx/Archive.h @@ -40,12 +40,15 @@ public: int Expand(int index, std::uint8_t*& buffer, bool null_terminated=false) const; int Expand(const char* filepath, std::uint8_t*& buffer, bool null_terminated=false) const; int Find(const char* filepath) const; + void UpdateBlockMap(); void PrintNamesOfEntries() const; + void PrintBlocks() const; std::size_t DirectoryBlocks() const; private: const char* path; Header header; std::vector entries; + std::vector blocks; }; -- cgit v1.1