10#include <mz_strm_os.h>
14#include <FileStream.h>
23 , tempZIPPath((std::filesystem::temp_directory_path() / (string::generateUUIDv4() +
".zip")).string()) {}
29std::unique_ptr<PackFile>
ZIP::create(
const std::string& path) {
31 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
39 .write(std::array<uint16_t, 4>{})
40 .write(std::array<uint32_t, 2>{})
47 if (!std::filesystem::exists(path)) {
52 auto* zip =
new ZIP{path};
53 auto packFile = std::unique_ptr<PackFile>(zip);
55 if (!zip->openZIP(zip->fullFilePath)) {
59 for (
auto code = mz_zip_goto_first_entry(zip->zipHandle); code == MZ_OK; code = mz_zip_goto_next_entry(zip->zipHandle)) {
60 if (mz_zip_entry_is_dir(zip->zipHandle) == MZ_OK) {
64 mz_zip_file* fileInfo =
nullptr;
65 if (mz_zip_entry_get_info(zip->zipHandle, &fileInfo)) {
69 auto entryPath = zip->cleanEntryPath(fileInfo->filename);
72 entry.
flags = fileInfo->compression_method << 16;
73 entry.
length = fileInfo->uncompressed_size;
75 entry.
crc32 = fileInfo->crc;
77 zip->entries.insert(entryPath, entry);
80 callback(entryPath, entry);
91std::optional<std::vector<std::byte>>
ZIP::readEntry(
const std::string& path_)
const {
105 if (mz_zip_locate_entry(this->
zipHandle, path.c_str(), !this->isCaseSensitive()) != MZ_OK) {
108 if (mz_zip_entry_read_open(this->
zipHandle, 0,
nullptr) != MZ_OK) {
111 std::vector<std::byte> out;
112 out.resize(entry->length);
113 mz_zip_entry_read(this->
zipHandle, out.data(),
static_cast<int>(entry->length));
120 entry.
length = buffer.size();
128 const std::string outputPath = outputDir +
'/' + this->
getFilename();
138 std::filesystem::rename(this->
tempZIPPath, outputPath);
139 if (!this->
openZIP(outputPath)) {
153 if (this->
entries.count(path)) {
161 if (this->
entries.count(path)) {
162 this->
entries.at(path).flags = (
static_cast<uint32_t
>(type) << 16) | (this->
entries.at(path).flags & 0xffff);
168 if (this->
entries.count(path)) {
169 return static_cast<int16_t
>(this->
entries.at(path).flags & 0xffff);
176 if (this->
entries.count(path)) {
177 this->
entries.at(path).flags = (this->
entries.at(path).flags & 0xffff0000) | strength;
182 void* writeStreamHandle = mz_stream_os_create();
183 if (mz_stream_open(writeStreamHandle, writeZipPath.c_str(), MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE)) {
187 void* writeZipHandle = mz_zip_writer_create();
188 if (mz_zip_writer_open(writeZipHandle, writeStreamHandle, 0)) {
192 mz_zip_set_version_madeby(writeZipHandle, MZ_VERSION_MADEBY);
194 const auto time = std::time(
nullptr);
198 bool noneFailed =
true;
199 this->
runForAllEntries([
this, &options, &callback, writeZipHandle, time, overrideCompression, &noneFailed](
const std::string& path,
const Entry& entry) {
205 if (overrideCompression) {
209 mz_zip_writer_set_compress_method(writeZipHandle, entry.
flags >> 16);
213 mz_zip_entry fileInfo{};
214 fileInfo.filename = path.c_str();
215 fileInfo.filename_size = path.length();
216 fileInfo.version_madeby = MZ_VERSION_MADEBY;
217 fileInfo.creation_date = time;
218 fileInfo.modified_date = time;
220 fileInfo.flag = MZ_ZIP_FLAG_DATA_DESCRIPTOR | MZ_ZIP_FLAG_UTF8;
221 fileInfo.uncompressed_size =
static_cast<int64_t
>(entry.
length);
223 fileInfo.crc = entry.
crc32;
224 if (mz_zip_writer_add_buffer(writeZipHandle, binData->data(),
static_cast<int>(binData->size()), &fileInfo)) {
230 callback(path, entry);
234 if (mz_zip_writer_close(writeZipHandle)) {
237 mz_zip_writer_delete(&writeZipHandle);
239 if (mz_stream_close(writeStreamHandle)) {
242 mz_stream_delete(&writeStreamHandle);
249 if (mz_stream_open(this->
streamHandle, path.data(), MZ_OPEN_MODE_READ) != MZ_OK) {
This class represents the metadata that a file has inside a PackFile.
uint32_t flags
Format-specific flags (PCK: File flags, VPK: Internal parser state, ZIP: Compression method / strengt...
uint64_t compressedLength
If the format supports compression, this is the compressed length.
uint32_t crc32
CRC32 checksum - 0 if unused.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
EntryCallbackBase< void > EntryCallback
void mergeUnbakedEntries()
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
std::vector< std::string > verifyEntryChecksumsUsingCRC32() const
std::string getFilename() const
/home/user/pak01_dir.vpk -> pak01_dir.vpk
std::string getBakeOutputDir(const std::string &outputDir) const
void runForAllEntries(const EntryCallback &operation, bool includeUnbaked=true) const
Run a callback for each entry in the pack file.
void setFullFilePath(const std::string &outputDir)
std::string cleanEntryPath(const std::string &path) const
static Entry createNewEntry()
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
ZIP(const std::string &fullFilePath_)
const std::string tempZIPPath
void setEntryCompressionType(const std::string &path_, EntryCompressionType type)
void setEntryCompressionStrength(const std::string &path_, int16_t strength)
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a ZIP file.
std::vector< std::string > verifyEntryChecksums() const override
Verify the checksums of each file, if a file fails the check its path will be added to the vector If ...
int16_t getEntryCompressionStrength(const std::string &path_) const
bool openZIP(std::string_view path)
bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback) override
If output folder is an empty string, it will overwrite the original.
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
bool bakeTempZip(const std::string &writeZipPath, BakeOptions options, const EntryCallback &callback) const
static std::unique_ptr< PackFile > create(const std::string &path)
Create a ZIP file.
EntryCompressionType getEntryCompressionType(const std::string &path_) const
uint32_t computeCRC32(std::span< const std::byte > buffer)
EntryCompressionType zip_compressionTypeOverride
BSP/ZIP - Override compression type of all stored entries.
int16_t zip_compressionStrength
BSP/VPK/ZIP - Compression strength.
EntryCompressionType zip_compressionType
BSP/ZIP - The compression format.
int16_t zip_compressionStrength
BSP/ZIP - The compression strength.