summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAki <please@ignore.pl>2022-08-07 22:38:21 +0200
committerAki <please@ignore.pl>2022-08-07 22:38:21 +0200
commitc5657b5cf6e72df9f573f149fe027374bf634fa7 (patch)
tree7b69d550e3b591bc31530c33437e6a5107af65bd
parent9ae3b193c461b168336d1d9e272aa834705633d7 (diff)
downloadstarshatter-c5657b5cf6e72df9f573f149fe027374bf634fa7.zip
starshatter-c5657b5cf6e72df9f573f149fe027374bf634fa7.tar.gz
starshatter-c5657b5cf6e72df9f573f149fe027374bf634fa7.tar.bz2
Added method to expand stored files
-rw-r--r--ArchiveEx/Archive.cpp37
-rw-r--r--ArchiveEx/Archive.h1
2 files changed, 35 insertions, 3 deletions
diff --git a/ArchiveEx/Archive.cpp b/ArchiveEx/Archive.cpp
index d714e46..3eea0fe 100644
--- a/ArchiveEx/Archive.cpp
+++ b/ArchiveEx/Archive.cpp
@@ -1,5 +1,6 @@
#include "Archive.h"
+#include <cstdint>
#include <cstdio>
#include <memory>
#include <vector>
@@ -28,7 +29,7 @@ Archive::Archive(const char* p) :
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());
+ std::size_t length = std::fread(&header, sizeof(Header), 1, file.get());
if (1 != length)
throw "could not read";
if (VERSION != header.version)
@@ -36,7 +37,7 @@ Archive::Archive(const char* p) :
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);
+ std::vector<Bytef> 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";
@@ -44,7 +45,7 @@ Archive::Archive(const char* p) :
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(
+ err = uncompress(
reinterpret_cast<Bytef*>(entries.data()),
&uncompressed_size,
compressed.data(),
@@ -54,6 +55,36 @@ Archive::Archive(const char* p) :
}
+int
+Archive::Expand(const int index, std::uint8_t*& buffer, const bool null_terminated) const
+{
+ if (0 > index && static_cast<int>(header.total_entries) <= index)
+ return -1; // Can be replaced by error-checked access to std::vector holding entries.
+ UniqueFileHandle file {std::fopen(path, "rb"), &std::fclose};
+ if (!file)
+ return -1;
+ const auto& entry = entries[index];
+ std::vector<Bytef> compressed(entry.compressed_size);
+ int err = std::fseek(file.get(), sizeof(Header) + entry.offset, SEEK_SET);
+ if (-1 == err)
+ return -1;
+ std::size_t length = std::fread(compressed.data(), 1, entry.compressed_size, file.get());
+ if (entry.compressed_size != length)
+ return -1;
+ uLongf output_length = entry.original_size + static_cast<uLongf>(null_terminated);
+ std::unique_ptr<std::uint8_t[]> uncompressed(new std::uint8_t[output_length]);
+ if (!uncompressed)
+ return -1;
+ err = uncompress(uncompressed.get(), &output_length, compressed.data(), entry.compressed_size);
+ if (Z_OK != err)
+ return -1;
+ buffer = uncompressed.release();
+ if (null_terminated)
+ buffer[output_length - 1] = 0;
+ return output_length;
+}
+
+
void
Archive::PrintNamesOfEntries() const
{
diff --git a/ArchiveEx/Archive.h b/ArchiveEx/Archive.h
index cc06dc4..6870194 100644
--- a/ArchiveEx/Archive.h
+++ b/ArchiveEx/Archive.h
@@ -39,6 +39,7 @@ class Archive
{
public:
explicit Archive(const char* path);
+ int Expand(int index, std::uint8_t*& buffer, bool null_terminated=false) const;
void PrintNamesOfEntries() const;
std::size_t DirectoryBlocks() const;
private: