diff options
Diffstat (limited to 'ArchiveEx/Archive.cpp')
-rw-r--r-- | ArchiveEx/Archive.cpp | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/ArchiveEx/Archive.cpp b/ArchiveEx/Archive.cpp new file mode 100644 index 0000000..d714e46 --- /dev/null +++ b/ArchiveEx/Archive.cpp @@ -0,0 +1,82 @@ +#include "Archive.h" + +#include <cstdio> +#include <memory> +#include <vector> + +#include <zlib.h> + + +namespace Archive +{ + + +using UniqueFileHandle = std::unique_ptr<std::FILE, decltype(&std::fclose)>; + + +static constexpr std::size_t DIRECTORY_MARGIN {64}; + + +static std::size_t BytesToBlocks(std::size_t bytes); + + +Archive::Archive(const char* p) : + path {p}, + header {}, + entries {} +{ + UniqueFileHandle file {std::fopen(path, "rb"), &std::fclose}; + if (!file) + throw "could not open archive"; + std::size_t length = fread(&header, sizeof(Header), 1, file.get()); + if (1 != length) + throw "could not read"; + if (VERSION != header.version) + throw "bad version"; + int err = std::fseek(file.get(), sizeof(Header) + header.directory.offset, SEEK_SET); + if (-1 == err) + throw "could not find directory in archive"; + std::vector<std::uint8_t> compressed(header.directory.compressed_size); + length = std::fread(compressed.data(), 1, header.directory.compressed_size, file.get()); + if (header.directory.compressed_size != length) + throw "could not read compressed directory"; + const std::size_t total_entries = header.total_entries + DIRECTORY_MARGIN; + entries.resize(header.total_entries); + entries.reserve(total_entries); // In original impl entries were switched on/off with their uncompressed size value. + uLongf uncompressed_size = sizeof(Entry) * total_entries; + err = ::uncompress( + reinterpret_cast<Bytef*>(entries.data()), + &uncompressed_size, + compressed.data(), + header.directory.compressed_size); + if (Z_OK != err) + throw "could not uncompress directory"; +} + + +void +Archive::PrintNamesOfEntries() const +{ + for (const auto& entry : entries) + std::printf("%s\n", entry.name); +} + + +std::size_t +Archive::DirectoryBlocks() const +{ + const std::size_t blocks = BytesToBlocks(header.total_entries * sizeof(Entry)); + return blocks == 0 ? 1 : blocks; +} + + +std::size_t +BytesToBlocks(const std::size_t bytes) +{ + const std::size_t full = bytes / BLOCK_SIZE; + const std::size_t partial = (bytes % BLOCK_SIZE) > 0; + return full + partial; +} + + +} // namespace Archive |