Patch miniz instead to allow specifying the compression method.

This commit is contained in:
Dario 2024-07-27 16:39:56 -03:00
parent b53d7f7611
commit fa373f0b8a
3 changed files with 16 additions and 79 deletions

View File

@ -6198,12 +6198,13 @@ static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_fil
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
{
return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);
return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0, MZ_DEFLATED);
}
mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size,
mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified,
const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len,
mz_uint16 compression_method)
{
mz_uint16 method = 0, dos_time = 0, dos_date = 0;
mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
@ -6344,7 +6345,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_n
if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
{
method = MZ_DEFLATED;
method = compression_method;
}
if (pState->m_zip64)

View File

@ -1359,7 +1359,7 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *
MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
const char *user_extra_data_central, mz_uint user_extra_data_central_len);
const char *user_extra_data_central, mz_uint user_extra_data_central_len, mz_uint16 compression_method);
/* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */
/* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/

View File

@ -384,6 +384,7 @@ int main(int argc, char *argv[]) {
compressionFailed = false;
mz_uint16 compressionMethod = MZ_ZSTD;
if (args.hasOption("deflate", "d")) {
fprintf(stdout, "Using deflate for compression.\n");
useZstd = false;
@ -391,6 +392,7 @@ int main(int argc, char *argv[]) {
}
else if (args.hasOption("store", "d")) {
fprintf(stdout, "Disabling compression.\n");
compressionMethod = MZ_DEFLATED;
useZstd = false;
useCompression = false;
}
@ -436,7 +438,7 @@ int main(int argc, char *argv[]) {
std::filesystem::path packPath = searchDirectory / packName;
std::string packPathStr = packPath.u8string();
mz_zip_archive zipArchive = {};
if (!mz_zip_writer_init_file(&zipArchive, packPathStr.c_str(), 0)) {
if (!mz_zip_writer_init_file_v2(&zipArchive, packPathStr.c_str(), 0, MZ_ZIP_FLAG_WRITE_ZIP64)) {
fprintf(stderr, "Failed to open %s for writing.\n", packPathStr.c_str());
return 1;
}
@ -490,7 +492,7 @@ int main(int argc, char *argv[]) {
if (!output.zipPath.empty()) {
mz_uint flags = useCompression ? MZ_ZIP_FLAG_COMPRESSED_DATA : 0;
if (!mz_zip_writer_add_mem_ex(&zipArchive, output.zipPath.c_str(), output.fileData.data(), output.fileData.size(), nullptr, 0, flags, useCompression ? output.uncompressedSize : 0, output.checksum)) {
if (!mz_zip_writer_add_mem_ex_v2(&zipArchive, output.zipPath.c_str(), output.fileData.data(), output.fileData.size(), nullptr, 0, flags, useCompression ? output.uncompressedSize : 0, output.checksum, nullptr, nullptr, 0, nullptr, 0, compressionMethod)) {
fprintf(stderr, "Failed to add %s to pack.\n", output.zipPath.c_str());
compressionFailed = true;
}
@ -509,83 +511,17 @@ int main(int argc, char *argv[]) {
}
if (!compressionFailed) {
mz_zip_writer_finalize_archive(&zipArchive);
}
mz_zip_writer_end(&zipArchive);
// Since miniz doesn't provide a way to write the compression method out, we just read the file and store all the offsets where we need to patch the compression method.
if (useCompression && useZstd) {
fprintf(stdout, "Reading pack...\n");
zipArchive = {};
if (mz_zip_reader_init_file(&zipArchive, packPathStr.c_str(), MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
std::vector<size_t> localHeaderOffsets;
std::vector<size_t> centralDirOffsets;
uint32_t fileCount = mz_zip_reader_get_num_files(&zipArchive);
mz_zip_archive_file_stat fileStat = {};
for (uint32_t i = 0; i < fileCount; i++) {
if (!mz_zip_reader_file_stat(&zipArchive, i, &fileStat)) {
fprintf(stderr, "Failed to open %s for reading.\n", packPathStr.c_str());
compressionFailed = false;
break;
}
localHeaderOffsets.emplace_back(fileStat.m_local_header_ofs);
centralDirOffsets.emplace_back(zipArchive.m_central_directory_file_ofs + fileStat.m_central_dir_ofs);
}
mz_zip_reader_end(&zipArchive);
if (!compressionFailed) {
fprintf(stdout, "Patching zstd compression method into headers...\n");
std::fstream zipStream(packPath, std::ios::binary | std::ios::in | std::ios::out);
if (zipStream.is_open()) {
auto patchMethod = [&](size_t absoluteOffset) {
// Validate that the method is being patched at the offset.
uint16_t readMethod = 0;
zipStream.seekg(absoluteOffset);
zipStream.read(reinterpret_cast<char *>(&readMethod), sizeof(readMethod));
if (readMethod != MZ_DEFLATED) {
fprintf(stderr, "Failed to patch compression method.\n");
compressionFailed = false;
return false;
}
// Write the patched method.
const uint16_t writeMethod = MZ_ZSTD;
zipStream.seekg(absoluteOffset);
zipStream.write(reinterpret_cast<const char *>(&writeMethod), sizeof(writeMethod));
return true;
};
for (uint32_t offset : localHeaderOffsets) {
if (!patchMethod(offset + MZ_ZIP_LDH_METHOD_OFS)) {
break;
}
}
for (uint32_t offset : centralDirOffsets) {
if (!patchMethod(offset + MZ_ZIP_CDH_METHOD_OFS)) {
break;
}
}
zipStream.seekg(0, std::ios::end);
zipStream.close();
}
else {
fprintf(stderr, "Failed to open %s for reading and writing.\n", packPathStr.c_str());
compressionFailed = false;
}
}
}
else {
fprintf(stderr, "Failed to open %s for reading.\n", packPathStr.c_str());
if (!mz_zip_writer_finalize_archive(&zipArchive)) {
fprintf(stderr, "Failed to finalize archive %s.\n", packPathStr.c_str());
compressionFailed = true;
}
}
if (!mz_zip_writer_end(&zipArchive)) {
fprintf(stderr, "Failed to close %s for writing.\n", packPathStr.c_str());
compressionFailed = true;
}
if (compressionFailed) {
std::filesystem::remove(packPath);
fprintf(stderr, "Pack creation has failed.\n");