10#include <mz_strm_os.h>
14#include <FileStream.h>
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));
119 uint8_t xzpVersion = 0;
120 mz_zip_get_valve_xzp_version(this->
zipHandle, &xzpVersion);
121 return xzpVersion == 2 || xzpVersion == 3;
126 entry.
length = buffer.size();
134 const std::string outputPath = outputDir +
'/' + this->
getFilename();
144 std::filesystem::rename(this->
tempZIPPath, outputPath);
145 if (!this->
openZIP(outputPath)) {
159 if (this->
entries.count(path)) {
167 if (this->
entries.count(path)) {
168 this->
entries.at(path).flags = (
static_cast<uint32_t
>(
type) << 16) | (this->
entries.at(path).flags & 0xffff);
174 if (this->
entries.count(path)) {
175 return static_cast<int16_t
>(this->
entries.at(path).flags & 0xffff);
182 if (this->
entries.count(path)) {
183 this->
entries.at(path).flags = (this->
entries.at(path).flags & 0xffff0000) | strength;
188 void* writeStreamHandle = mz_stream_os_create();
189 if (mz_stream_open(writeStreamHandle, writeZipPath.c_str(), MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE)) {
193 void* writeZipHandle = mz_zip_writer_create();
194 if (mz_zip_writer_open(writeZipHandle, writeStreamHandle, 0)) {
198 mz_zip_set_version_madeby(writeZipHandle, MZ_VERSION_MADEBY);
200 const auto modifiedTime = std::time(
nullptr);
201 const auto modifiedTimeDOS = mz_zip_time_t_to_dos_date(modifiedTime);
205 bool noneFailed =
true;
206 this->
runForAllEntries([
this, &options, &callback, writeZipHandle, modifiedTime, modifiedTimeDOS, overrideCompression, &noneFailed](
const std::string& path,
const Entry& entry) {
207 const auto binData = this->
readEntry(path);
212 if (overrideCompression) {
216 mz_zip_writer_set_compress_method(writeZipHandle, entry.
flags >> 16);
220 mz_zip_entry fileInfo{};
221 fileInfo.filename = path.c_str();
222 fileInfo.filename_size = path.length();
223 fileInfo.version_madeby = MZ_VERSION_MADEBY;
224 fileInfo.creation_date = modifiedTime;
225 fileInfo.modified_date = modifiedTimeDOS;
227 fileInfo.flag = MZ_ZIP_FLAG_DATA_DESCRIPTOR | MZ_ZIP_FLAG_UTF8;
228 fileInfo.uncompressed_size =
static_cast<int64_t
>(entry.
length);
230 fileInfo.crc = entry.
crc32;
231 if (mz_zip_writer_add_buffer(writeZipHandle, binData->data(),
static_cast<int>(binData->size()), &fileInfo)) {
237 callback(path, entry);
241 if (mz_zip_writer_close(writeZipHandle)) {
244 mz_zip_writer_delete(&writeZipHandle);
246 if (mz_stream_close(writeStreamHandle)) {
249 mz_stream_delete(&writeStreamHandle);
256 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.
virtual operator std::string() const
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
PackFile(const PackFile &other)=delete
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.
bool isReadOnly() const noexcept override
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.