summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-08-09 23:52:11 +0200
committerAki <please@ignore.pl>2022-08-09 23:52:11 +0200
commita1bb81360e7f1964498de82dfc0c3f6ff3037182 (patch)
tree64ef562cf7bbcb41d10a0e7d1bc3ec59dce1448c
parenta88cfc3a560f372f5abcff09fcbf8393c1f0bd55 (diff)
downloadstarshatter-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.cpp45
-rw-r--r--ArchiveEx/Archive.h3
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;
};