diff options
author | Aki <please@ignore.pl> | 2022-08-09 23:52:11 +0200 |
---|---|---|
committer | Aki <please@ignore.pl> | 2022-08-09 23:52:11 +0200 |
commit | a1bb81360e7f1964498de82dfc0c3f6ff3037182 (patch) | |
tree | 64ef562cf7bbcb41d10a0e7d1bc3ec59dce1448c | |
parent | a88cfc3a560f372f5abcff09fcbf8393c1f0bd55 (diff) | |
download | starshatter-a1bb81360e7f1964498de82dfc0c3f6ff3037182.zip starshatter-a1bb81360e7f1964498de82dfc0c3f6ff3037182.tar.gz starshatter-a1bb81360e7f1964498de82dfc0c3f6ff3037182.tar.bz2 |
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.
-rw-r--r-- | ArchiveEx/Archive.cpp | 45 | ||||
-rw-r--r-- | ArchiveEx/Archive.h | 3 |
2 files changed, 48 insertions, 0 deletions
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<Entry> entries; + std::vector<int> blocks; }; |