From de453fed1d611ec324301e9a17d9d6fd1e44d534 Mon Sep 17 00:00:00 2001 From: Dave Allie Date: Mon, 8 Dec 2025 00:39:17 +1100 Subject: [PATCH] Stream inflated EPUB HTMLs down to disk instead of inflating in memory (#4) * Downgrade miniz for stability * Stream HTML from ZIP down to disk instead of loading all in mem --- lib/Epub/Epub.cpp | 20 +- lib/Epub/Epub.h | 5 +- lib/Epub/Epub/EpubHtmlParserSlim.cpp | 5 + lib/Epub/Epub/Section.cpp | 29 +- lib/ZipFile/ZipFile.cpp | 285 ++++++-- lib/ZipFile/ZipFile.h | 9 +- lib/miniz/miniz.c | 598 ++++++--------- lib/miniz/miniz.h | 1013 ++++++++++---------------- src/screens/EpubReaderScreen.cpp | 1 + 9 files changed, 857 insertions(+), 1108 deletions(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 83caf1d..3beaa54 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -9,7 +9,7 @@ bool Epub::findContentOpfFile(const ZipFile& zip, std::string& contentOpfFile) { // open up the meta data to find where the content.opf file lives size_t s; - const auto metaInfo = zip.readTextFileToMemory("META-INF/container.xml", &s); + const auto metaInfo = reinterpret_cast(zip.readFileToMemory("META-INF/container.xml", &s, true)); if (!metaInfo) { Serial.println("Could not find META-INF/container.xml"); return false; @@ -57,7 +57,7 @@ bool Epub::findContentOpfFile(const ZipFile& zip, std::string& contentOpfFile) { bool Epub::parseContentOpf(ZipFile& zip, std::string& content_opf_file) { // read in the content.opf file and parse it - auto contents = zip.readTextFileToMemory(content_opf_file.c_str()); + auto contents = reinterpret_cast(zip.readFileToMemory(content_opf_file.c_str(), nullptr, true)); // parse the contents tinyxml2::XMLDocument doc; @@ -168,7 +168,7 @@ bool Epub::parseTocNcxFile(const ZipFile& zip) { return false; } - const auto ncxData = zip.readTextFileToMemory(tocNcxItem.c_str()); + const auto ncxData = reinterpret_cast(zip.readFileToMemory(tocNcxItem.c_str(), nullptr, true)); if (!ncxData) { Serial.printf("Could not find %s\n", tocNcxItem.c_str()); return false; @@ -308,11 +308,11 @@ std::string normalisePath(const std::string& path) { return result; } -uint8_t* Epub::getItemContents(const std::string& itemHref, size_t* size) const { +uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, bool trailingNullByte) const { const ZipFile zip("/sd" + filepath); const std::string path = normalisePath(itemHref); - const auto content = zip.readFileToMemory(path.c_str(), size); + const auto content = zip.readFileToMemory(path.c_str(), size, trailingNullByte); if (!content) { Serial.printf("Failed to read item %s\n", path.c_str()); return nullptr; @@ -321,17 +321,11 @@ uint8_t* Epub::getItemContents(const std::string& itemHref, size_t* size) const return content; } -char* Epub::getTextItemContents(const std::string& itemHref, size_t* size) const { +bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const { const ZipFile zip("/sd" + filepath); const std::string path = normalisePath(itemHref); - const auto content = zip.readTextFileToMemory(path.c_str(), size); - if (!content) { - Serial.printf("Failed to read item %s\n", path.c_str()); - return nullptr; - } - - return content; + return zip.readFileToStream(path.c_str(), out, chunkSize); } int Epub::getSpineItemsCount() const { return spine.size(); } diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index b59dcfa..0a772b3 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -56,8 +56,9 @@ class Epub { const std::string& getPath() const; const std::string& getTitle() const; const std::string& getCoverImageItem() const; - uint8_t* getItemContents(const std::string& itemHref, size_t* size = nullptr) const; - char* getTextItemContents(const std::string& itemHref, size_t* size = nullptr) const; + uint8_t* readItemContentsToBytes(const std::string& itemHref, size_t* size = nullptr, + bool trailingNullByte = false) const; + bool readItemContentsToStream(const std::string& itemHref, Print& out, size_t chunkSize) const; std::string& getSpineItem(int spineIndex); int getSpineItemsCount() const; EpubTocEntry& getTocItem(int tocTndex); diff --git a/lib/Epub/Epub/EpubHtmlParserSlim.cpp b/lib/Epub/Epub/EpubHtmlParserSlim.cpp index cb425ee..50e588d 100644 --- a/lib/Epub/Epub/EpubHtmlParserSlim.cpp +++ b/lib/Epub/Epub/EpubHtmlParserSlim.cpp @@ -199,6 +199,11 @@ bool EpubHtmlParserSlim::parseAndBuildPages() { XML_SetCharacterDataHandler(parser, characterData); FILE* file = fopen(filepath, "r"); + if (!file) { + Serial.printf("Couldn't open file %s\n", filepath); + XML_ParserFree(parser); + return false; + } do { void* const buf = XML_GetBuffer(parser, 1024); diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index aa9ad95..dbc0457 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -64,35 +64,28 @@ void Section::setupCacheDir() const { void Section::clearCache() const { SD.rmdir(cachePath.c_str()); } bool Section::persistPageDataToSD() { - size_t size = 0; - auto localPath = epub->getSpineItem(spineIndex); + const auto localPath = epub->getSpineItem(spineIndex); - const auto html = epub->getItemContents(epub->getSpineItem(spineIndex), &size); - if (!html) { - Serial.println("Failed to read item contents"); - return false; - } - - // TODO: Would love to stream this through an XML visitor + // TODO: Should we get rid of this file all together? + // It currently saves us a bit of memory by allowing for all the inflation bits to be released + // before loading the XML parser const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html"; - File f = SD.open(tmpHtmlPath.c_str(), FILE_WRITE); - const auto written = f.write(html, size); + File f = SD.open(tmpHtmlPath.c_str(), FILE_WRITE, true); + bool success = epub->readItemContentsToStream(localPath, f, 1024); f.close(); - free(html); - Serial.printf("Wrote %d bytes to %s\n", written, tmpHtmlPath.c_str()); - - if (size != written) { - Serial.println("Failed to inflate section contents to SD"); - SD.remove(tmpHtmlPath.c_str()); + if (!success) { + Serial.println("Failed to stream item contents"); return false; } + Serial.printf("Streamed HTML to %s\n", tmpHtmlPath.c_str()); + const auto sdTmpHtmlPath = "/sd" + tmpHtmlPath; auto visitor = EpubHtmlParserSlim(sdTmpHtmlPath.c_str(), renderer, [this](const Page* page) { this->onPageComplete(page); }); - const bool success = visitor.parseAndBuildPages(); + success = visitor.parseAndBuildPages(); SD.remove(tmpHtmlPath.c_str()); if (!success) { diff --git a/lib/ZipFile/ZipFile.cpp b/lib/ZipFile/ZipFile.cpp index 0834838..a6dbbe8 100644 --- a/lib/ZipFile/ZipFile.cpp +++ b/lib/ZipFile/ZipFile.cpp @@ -3,51 +3,37 @@ #include #include -int libzInflateOneShot(const uint8_t* inputBuff, const size_t compSize, uint8_t* outputBuff, const size_t uncompSize) { - mz_stream pStream = { - .next_in = inputBuff, - .avail_in = compSize, - .total_in = 0, - .next_out = outputBuff, - .avail_out = uncompSize, - .total_out = 0, - }; +bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) { + // Setup inflator + const auto inflator = static_cast(malloc(sizeof(tinfl_decompressor))); + if (!inflator) { + Serial.println("Failed to allocate memory for inflator"); + return false; + } + memset(inflator, 0, sizeof(tinfl_decompressor)); + tinfl_init(inflator); - int status = 0; - status = mz_inflateInit2(&pStream, -MZ_DEFAULT_WINDOW_BITS); + size_t inBytes = deflatedSize; + size_t outBytes = inflatedSize; + const tinfl_status status = tinfl_decompress(inflator, inputBuf, &inBytes, nullptr, outputBuf, &outBytes, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + free(inflator); - if (status != MZ_OK) { - Serial.printf("inflateInit2 failed: %d\n", status); - return status; + if (status != TINFL_STATUS_DONE) { + Serial.printf("tinfl_decompress() failed with status %d\n", status); + return false; } - status = mz_inflate(&pStream, MZ_FINISH); - if (status != MZ_STREAM_END) { - Serial.printf("inflate failed: %d\n", status); - return status; - } - - status = mz_inflateEnd(&pStream); - if (status != MZ_OK) { - Serial.printf("inflateEnd failed: %d\n", status); - return status; - } - - return status; + return true; } -char* ZipFile::readTextFileToMemory(const char* filename, size_t* size) const { - const auto data = readFileToMemory(filename, size, true); - return data ? reinterpret_cast(data) : nullptr; -} - -uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, bool trailingNullByte) const { +bool ZipFile::loadFileStat(const char* filename, mz_zip_archive_file_stat* fileStat) const { mz_zip_archive zipArchive = {}; const bool status = mz_zip_reader_init_file(&zipArchive, filePath.c_str(), 0); if (!status) { Serial.printf("mz_zip_reader_init_file() failed!\nError %s\n", mz_zip_get_error_string(zipArchive.m_last_error)); - return nullptr; + return false; } // find the file @@ -55,41 +41,57 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, bool trai if (!mz_zip_reader_locate_file_v2(&zipArchive, filename, nullptr, 0, &fileIndex)) { Serial.printf("Could not find file %s\n", filename); mz_zip_reader_end(&zipArchive); - return nullptr; + return false; } - mz_zip_archive_file_stat fileStat; - if (!mz_zip_reader_file_stat(&zipArchive, fileIndex, &fileStat)) { + if (!mz_zip_reader_file_stat(&zipArchive, fileIndex, fileStat)) { Serial.printf("mz_zip_reader_file_stat() failed!\nError %s\n", mz_zip_get_error_string(zipArchive.m_last_error)); mz_zip_reader_end(&zipArchive); - return nullptr; + return false; } mz_zip_reader_end(&zipArchive); + return true; +} - uint8_t pLocalHeader[30]; - uint64_t fileOffset = fileStat.m_local_header_ofs; +long ZipFile::getDataOffset(const mz_zip_archive_file_stat& fileStat) const { + constexpr auto localHeaderSize = 30; - // Reopen the file to manual read out delated bytes - FILE* file = fopen(filePath.c_str(), "rb"); + uint8_t pLocalHeader[localHeaderSize]; + const uint64_t fileOffset = fileStat.m_local_header_ofs; + + FILE* file = fopen(filePath.c_str(), "r"); fseek(file, fileOffset, SEEK_SET); + const size_t read = fread(pLocalHeader, 1, localHeaderSize, file); + fclose(file); - const size_t read = fread(pLocalHeader, 1, 30, file); - if (read != 30) { + if (read != localHeaderSize) { Serial.println("Something went wrong reading the local header"); - fclose(file); - return nullptr; + return -1; } if (pLocalHeader[0] + (pLocalHeader[1] << 8) + (pLocalHeader[2] << 16) + (pLocalHeader[3] << 24) != 0x04034b50 /* MZ_ZIP_LOCAL_DIR_HEADER_SIG */) { Serial.println("Not a valid zip file header"); - fclose(file); - return nullptr; + return -1; } const uint16_t filenameLength = pLocalHeader[26] + (pLocalHeader[27] << 8); const uint16_t extraOffset = pLocalHeader[28] + (pLocalHeader[29] << 8); - fileOffset += 30 + filenameLength + extraOffset; + return fileOffset + localHeaderSize + filenameLength + extraOffset; +} + +uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const bool trailingNullByte) const { + mz_zip_archive_file_stat fileStat; + if (!loadFileStat(filename, &fileStat)) { + return nullptr; + } + + const long fileOffset = getDataOffset(fileStat); + if (fileOffset < 0) { + return nullptr; + } + + FILE* file = fopen(filePath.c_str(), "rb"); fseek(file, fileOffset, SEEK_SET); const auto deflatedDataSize = static_cast(fileStat.m_comp_size); @@ -97,15 +99,19 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, bool trai const auto dataSize = trailingNullByte ? inflatedDataSize + 1 : inflatedDataSize; const auto data = static_cast(malloc(dataSize)); - if (!fileStat.m_method) { + if (fileStat.m_method == MZ_NO_COMPRESSION) { // no deflation, just read content const size_t dataRead = fread(data, 1, inflatedDataSize, file); fclose(file); + if (dataRead != inflatedDataSize) { Serial.println("Failed to read data"); + free(data); return nullptr; } - } else { + + // Continue out of block with data set + } else if (fileStat.m_method == MZ_DEFLATED) { // Read out deflated content from file const auto deflatedData = static_cast(malloc(deflatedDataSize)); if (deflatedData == nullptr) { @@ -116,25 +122,186 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, bool trai const size_t dataRead = fread(deflatedData, 1, deflatedDataSize, file); fclose(file); + if (dataRead != deflatedDataSize) { Serial.printf("Failed to read data, expected %d got %d\n", deflatedDataSize, dataRead); free(deflatedData); + free(data); return nullptr; } - const int result = libzInflateOneShot(deflatedData, deflatedDataSize, data, inflatedDataSize); + bool success = inflateOneShot(deflatedData, deflatedDataSize, data, inflatedDataSize); free(deflatedData); - if (result != MZ_OK) { + + if (!success) { Serial.println("Failed to inflate file"); + free(data); return nullptr; } + + // Continue out of block with data set + } else { + Serial.println("Unsupported compression method"); + fclose(file); + return nullptr; } - if (trailingNullByte) { - data[inflatedDataSize] = '\0'; - } - if (size) { - *size = inflatedDataSize; - } + if (trailingNullByte) data[inflatedDataSize] = '\0'; + if (size) *size = inflatedDataSize; return data; } + +bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t chunkSize) const { + mz_zip_archive_file_stat fileStat; + if (!loadFileStat(filename, &fileStat)) { + return false; + } + + const long fileOffset = getDataOffset(fileStat); + if (fileOffset < 0) { + return false; + } + + FILE* file = fopen(filePath.c_str(), "rb"); + fseek(file, fileOffset, SEEK_SET); + + const auto deflatedDataSize = static_cast(fileStat.m_comp_size); + const auto inflatedDataSize = static_cast(fileStat.m_uncomp_size); + + if (fileStat.m_method == MZ_NO_COMPRESSION) { + // no deflation, just read content + const auto buffer = static_cast(malloc(chunkSize)); + if (!buffer) { + Serial.println("Failed to allocate memory for buffer"); + fclose(file); + return false; + } + + size_t remaining = inflatedDataSize; + while (remaining > 0) { + const size_t dataRead = fread(buffer, 1, remaining < chunkSize ? remaining : chunkSize, file); + if (dataRead == 0) { + Serial.println("Could not read more bytes"); + free(buffer); + fclose(file); + return false; + } + + out.write(buffer, dataRead); + remaining -= dataRead; + } + + fclose(file); + free(buffer); + return true; + } + + if (fileStat.m_method == MZ_DEFLATED) { + // Setup inflator + const auto inflator = static_cast(malloc(sizeof(tinfl_decompressor))); + if (!inflator) { + Serial.println("Failed to allocate memory for inflator"); + fclose(file); + return false; + } + memset(inflator, 0, sizeof(tinfl_decompressor)); + tinfl_init(inflator); + + // Setup file read buffer + const auto fileReadBuffer = static_cast(malloc(chunkSize)); + if (!fileReadBuffer) { + Serial.println("Failed to allocate memory for zip file read buffer"); + free(inflator); + fclose(file); + return false; + } + + const auto outputBuffer = static_cast(malloc(TINFL_LZ_DICT_SIZE)); + if (!outputBuffer) { + Serial.println("Failed to allocate memory for dictionary"); + free(inflator); + free(fileReadBuffer); + fclose(file); + return false; + } + memset(outputBuffer, 0, TINFL_LZ_DICT_SIZE); + + size_t fileRemainingBytes = deflatedDataSize; + size_t processedOutputBytes = 0; + size_t fileReadBufferFilledBytes = 0; + size_t fileReadBufferCursor = 0; + size_t outputCursor = 0; // Current offset in the circular dictionary + + while (true) { + // Load more compressed bytes when needed + if (fileReadBufferCursor >= fileReadBufferFilledBytes) { + if (fileRemainingBytes == 0) { + // Should not be hit, but a safe protection + break; // EOF + } + + fileReadBufferFilledBytes = + fread(fileReadBuffer, 1, fileRemainingBytes < chunkSize ? fileRemainingBytes : chunkSize, file); + fileRemainingBytes -= fileReadBufferFilledBytes; + fileReadBufferCursor = 0; + + if (fileReadBufferFilledBytes == 0) { + // Bad read + break; // EOF + } + } + + // Available bytes in fileReadBuffer to process + size_t inBytes = fileReadBufferFilledBytes - fileReadBufferCursor; + // Space remaining in outputBuffer + size_t outBytes = TINFL_LZ_DICT_SIZE - outputCursor; + + const tinfl_status status = tinfl_decompress(inflator, fileReadBuffer + fileReadBufferCursor, &inBytes, + outputBuffer, outputBuffer + outputCursor, &outBytes, + fileRemainingBytes > 0 ? TINFL_FLAG_HAS_MORE_INPUT : 0); + + // Update input position + fileReadBufferCursor += inBytes; + + // Write output chunk + if (outBytes > 0) { + processedOutputBytes += outBytes; + out.write(outputBuffer + outputCursor, outBytes); + // Update output position in buffer (with wraparound) + outputCursor = (outputCursor + outBytes) & (TINFL_LZ_DICT_SIZE - 1); + } + + Serial.printf("Decompressing - %d/%d deflated into %d/%d inflated\n", deflatedDataSize - fileRemainingBytes, + deflatedDataSize, processedOutputBytes, inflatedDataSize); + + if (status < 0) { + Serial.printf("tinfl_decompress() failed with status %d\n", status); + fclose(file); + free(outputBuffer); + free(fileReadBuffer); + free(inflator); + return false; + } + + if (status == TINFL_STATUS_DONE) { + Serial.println("Decompression finished"); + fclose(file); + free(inflator); + free(fileReadBuffer); + free(outputBuffer); + return true; + } + } + + // If we get here, EOF reached without TINFL_STATUS_DONE + Serial.println("Unexpected EOF"); + fclose(file); + free(outputBuffer); + free(fileReadBuffer); + free(inflator); + return false; + } + + Serial.println("Unsupported compression method"); + return false; +} diff --git a/lib/ZipFile/ZipFile.h b/lib/ZipFile/ZipFile.h index 9702072..36ac7c4 100644 --- a/lib/ZipFile/ZipFile.h +++ b/lib/ZipFile/ZipFile.h @@ -1,12 +1,19 @@ #pragma once +#include + +#include #include +#include "miniz.h" + class ZipFile { std::string filePath; + bool loadFileStat(const char* filename, mz_zip_archive_file_stat* fileStat) const; + long getDataOffset(const mz_zip_archive_file_stat& fileStat) const; public: explicit ZipFile(std::string filePath) : filePath(std::move(filePath)) {} ~ZipFile() = default; - char* readTextFileToMemory(const char* filename, size_t* size = nullptr) const; uint8_t* readFileToMemory(const char* filename, size_t* size = nullptr, bool trailingNullByte = false) const; + bool readFileToStream(const char* filename, Print& out, size_t chunkSize) const; }; diff --git a/lib/miniz/miniz.c b/lib/miniz/miniz.c index b6d7273..2eb5a9f 100644 --- a/lib/miniz/miniz.c +++ b/lib/miniz/miniz.c @@ -159,8 +159,6 @@ const char* mz_version(void) { return MZ_VERSION; } #ifndef MINIZ_NO_ZLIB_APIS -#ifndef MINIZ_NO_DEFLATE_APIS - int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } @@ -275,7 +273,7 @@ int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; @@ -301,10 +299,6 @@ int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - -#ifndef MINIZ_NO_INFLATE_APIS - typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; @@ -486,7 +480,7 @@ int mz_uncompress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned cha memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ - if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + if ((*pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)*pSource_len; @@ -511,8 +505,6 @@ int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char return mz_uncompress2(pDest, pDest_len, pSource, &source_len); } -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - const char* mz_error(int err) { static struct { int m_err; @@ -591,8 +583,6 @@ const char* mz_error(int err) { * **************************************************************************/ -#ifndef MINIZ_NO_DEFLATE_APIS - #ifdef __cplusplus extern "C" { #endif @@ -680,7 +670,7 @@ typedef struct { static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; - MZ_CLEAR_ARR(hist); + MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; @@ -774,7 +764,7 @@ static void tdefl_optimize_huffman_table(tdefl_compressor* d, int table_num, int int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; - MZ_CLEAR_ARR(num_codes); + MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { @@ -794,8 +784,8 @@ static void tdefl_optimize_huffman_table(tdefl_compressor* d, int table_num, int tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); - MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]); - MZ_CLEAR_ARR(d->m_huff_codes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } @@ -861,8 +851,8 @@ static void tdefl_optimize_huffman_table(tdefl_compressor* d, int table_num, int } \ } -static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, - 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, + 11, 4, 12, 3, 13, 2, 14, 1, 15}; static void tdefl_start_dynamic_block(tdefl_compressor* d) { int num_lit_codes, num_dist_codes, num_bit_lengths; @@ -976,8 +966,7 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor* d) { if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0]; - mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16*)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); @@ -1018,7 +1007,7 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor* d) { if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; - memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64)); + *(mz_uint64*)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; @@ -1090,8 +1079,6 @@ static mz_bool tdefl_compress_block(tdefl_compressor* d, mz_bool static_block) { return tdefl_compress_lz_codes(d); } -static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; - static int tdefl_flush_block(tdefl_compressor* d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8* pSaved_output_buf; @@ -1114,27 +1101,8 @@ static int tdefl_flush_block(tdefl_compressor* d, int flush) { d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { - const mz_uint8 cmf = 0x78; - mz_uint8 flg, flevel = 3; - mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint); - - /* Determine compression level by reversing the process in tdefl_create_comp_flags_from_zip_params() */ - for (i = 0; i < mz_un; i++) - if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF)) break; - - if (i < 2) - flevel = 0; - else if (i < 6) - flevel = 1; - else if (i == 6) - flevel = 2; - - header = cmf << 8 | (flevel << 6); - header += 31 - (header % 31); - flg = header & 0xFF; - - TDEFL_PUT_BITS(cmf, 8); - TDEFL_PUT_BITS(flg, 8); + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); @@ -1550,7 +1518,7 @@ static mz_bool tdefl_compress_normal(tdefl_compressor* d) { mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); - const mz_uint8* pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL; + const mz_uint8* pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { @@ -1720,8 +1688,8 @@ tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pI if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { - MZ_CLEAR_ARR(d->m_hash); - MZ_CLEAR_ARR(d->m_next); + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } @@ -1741,7 +1709,7 @@ tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_fun d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_ARR(d->m_hash); + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = @@ -1763,7 +1731,7 @@ tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_fun d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_ARR(d->m_dict); + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_dict); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; @@ -1836,6 +1804,8 @@ size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* return out_buf.m_size; } +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine * if throughput to fall off a cliff on some files). */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { @@ -1941,7 +1911,7 @@ void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ -tdefl_compressor* tdefl_compressor_alloc(void) { return (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); } +tdefl_compressor* tdefl_compressor_alloc() { return (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); } void tdefl_compressor_free(tdefl_compressor* pComp) { MZ_FREE(pComp); } #endif @@ -1953,35 +1923,31 @@ void tdefl_compressor_free(tdefl_compressor* pComp) { MZ_FREE(pComp); } #ifdef __cplusplus } #endif - -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - /************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ - -#ifndef MINIZ_NO_INFLATE_APIS +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ #ifdef __cplusplus extern "C" { @@ -2057,22 +2023,22 @@ extern "C" { /* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, * and tries again until it succeeds or until the */ /* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ -#define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \ - do { \ - temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); \ - if (temp >= 0) break; \ - } \ - TINFL_GET_BYTE(state_index, c); \ - bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ - num_bits += 8; \ +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ } while (num_bits < 15); /* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because @@ -2086,13 +2052,13 @@ extern "C" { * the case where the user passes in 1+zillion bytes */ /* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much * trickier. */ -#define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \ +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ do { \ int temp; \ mz_uint code_len, c; \ if (num_bits < 15) { \ if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ } else { \ bit_buf |= \ (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ @@ -2100,12 +2066,12 @@ extern "C" { num_bits += 16; \ } \ } \ - if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ - temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while (temp < 0); \ } \ sym = temp; \ @@ -2114,38 +2080,26 @@ extern "C" { } \ MZ_MACRO_END -static void tinfl_clear_tree(tinfl_decompressor* r) { - if (r->m_type == 0) - MZ_CLEAR_ARR(r->m_tree_0); - else if (r->m_type == 1) - MZ_CLEAR_ARR(r->m_tree_1); - else - MZ_CLEAR_ARR(r->m_tree_2); -} - tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size, mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size, const mz_uint32 decomp_flags) { - static const mz_uint16 s_length_base[31] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const mz_uint8 s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; - static const mz_uint16 s_dist_base[32] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, - 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, - 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; - static const mz_uint8 s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, - 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const int s_length_base[31] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; + static const int s_dist_base[32] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; static const mz_uint8 s_length_dezigzag[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - static const mz_uint16 s_min_table_sizes[3] = {257, 1, 4}; - - mz_int16* pTrees[3]; - mz_uint8* pCode_sizes[3]; + static const int s_min_table_sizes[3] = {257, 1, 4}; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next ? pOut_buf_next + *pOut_buf_size : NULL; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, @@ -2158,13 +2112,6 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex return TINFL_STATUS_BAD_PARAM; } - pTrees[0] = r->m_tree_0; - pTrees[1] = r->m_tree_1; - pTrees[2] = r->m_tree_2; - pCode_sizes[0] = r->m_code_size_0; - pCode_sizes[1] = r->m_code_size_1; - pCode_sizes[2] = r->m_code_size_2; - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; @@ -2181,7 +2128,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || - ((out_buf_size_mask + 1) < (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4))))); + ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } @@ -2229,11 +2176,11 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { - mz_uint8* p = r->m_code_size_0; + mz_uint8* p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; - TINFL_MEMSET(r->m_code_size_1, 5, 32); + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; @@ -2243,27 +2190,23 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_ARR(r->m_code_size_2); + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); - r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s; + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for (; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; - mz_int16* pLookUp; - mz_int16* pTree; - mz_uint8* pCode_size; + tinfl_huff_table* pTable; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; - pLookUp = r->m_look_up[r->m_type]; - pTree = pTrees[r->m_type]; - pCode_size = pCode_sizes[r->m_type]; - MZ_CLEAR_ARR(total_syms); - TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0])); - tinfl_clear_tree(r); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pCode_size[i]]++; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { @@ -2274,40 +2217,40 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { - mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index]; + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { - pLookUp[rev_code] = k; + pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { - pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); - if (!pTree[-tree_cur - 1]) { - pTree[-tree_cur - 1] = (mz_int16)tree_next; + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else - tree_cur = pTree[-tree_cur - 1]; + tree_cur = pTable->m_tree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); - pTree[-tree_cur - 1] = (mz_int16)sym_index; + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { mz_uint s; - TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2); + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; @@ -2324,15 +2267,15 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } - TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]); - TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for (;;) { mz_uint8* pSrc; for (;;) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { - TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0); + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); @@ -2354,12 +2297,12 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex num_bits += 16; } #endif - if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { - sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; @@ -2374,12 +2317,12 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex num_bits += 16; } #endif - if ((sym2 = r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { - sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)]; + sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; @@ -2405,7 +2348,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex counter += extra_bits; } - TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1); + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { @@ -2479,7 +2422,7 @@ tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_nex --pIn_buf_cur; num_bits -= 8; } - bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits); + bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ @@ -2510,7 +2453,7 @@ common_exit: } } r->m_num_bits = num_bits; - r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits); + r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; @@ -2599,7 +2542,6 @@ int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, mz_uint8* pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; - memset(pDict, 0, TINFL_LZ_DICT_SIZE); tinfl_init(&decomp); for (;;) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; @@ -2620,7 +2562,7 @@ int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, } #ifndef MINIZ_NO_MALLOC -tinfl_decompressor* tinfl_decompressor_alloc(void) { +tinfl_decompressor* tinfl_decompressor_alloc() { tinfl_decompressor* pDecomp = (tinfl_decompressor*)MZ_MALLOC(sizeof(tinfl_decompressor)); if (pDecomp) tinfl_init(pDecomp); return pDecomp; @@ -2632,34 +2574,32 @@ void tinfl_decompressor_free(tinfl_decompressor* pDecomp) { MZ_FREE(pDecomp); } #ifdef __cplusplus } #endif - -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - /************************************************************************** - * - * Copyright 2013-2014 RAD Game Tools and Valve Software - * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC - * Copyright 2016 Martin Raiber - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - **************************************************************************/ +/************************************************************************** + * + * Copyright 2013-2014 RAD Game Tools and Valve Software + * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC + * Copyright 2016 Martin Raiber + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ #ifndef MINIZ_NO_ARCHIVE_APIS @@ -2674,62 +2614,17 @@ extern "C" { #else #include -#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef __cplusplus -#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0 -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include - -static WCHAR* mz_utf8z_to_widechar(const char* str) { - int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - WCHAR* wStr = (WCHAR*)malloc(reqChars * sizeof(WCHAR)); - MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars); - return wStr; -} - +#if defined(_MSC_VER) || defined(__MINGW64__) static FILE* mz_fopen(const char* pFilename, const char* pMode) { - WCHAR* wFilename = mz_utf8z_to_widechar(pFilename); - WCHAR* wMode = mz_utf8z_to_widechar(pMode); FILE* pFile = NULL; - errno_t err = _wfopen_s(&pFile, wFilename, wMode); - free(wFilename); - free(wMode); - return err ? NULL : pFile; + fopen_s(&pFile, pFilename, pMode); + return pFile; } - static FILE* mz_freopen(const char* pPath, const char* pMode, FILE* pStream) { - WCHAR* wPath = mz_utf8z_to_widechar(pPath); - WCHAR* wMode = mz_utf8z_to_widechar(pMode); FILE* pFile = NULL; - errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); - free(wPath); - free(wMode); - return err ? NULL : pFile; + if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; + return pFile; } - -#if defined(__MINGW32__) -static int mz_stat(const char* path, struct _stat* buffer) { - WCHAR* wPath = mz_utf8z_to_widechar(path); - int res = _wstat(wPath, buffer); - free(wPath); - return res; -} -#else -static int mz_stat64(const char* path, struct __stat64* buffer) { - WCHAR* wPath = mz_utf8z_to_widechar(path); - int res = _wstat64(wPath, buffer); - free(wPath); - return res; -} -#endif - #ifndef MINIZ_NO_TIME #include #endif @@ -2739,18 +2634,12 @@ static int mz_stat64(const char* path, struct __stat64* buffer) { #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 -#if defined(__MINGW32__) -#define MZ_FILE_STAT_STRUCT _stat -#define MZ_FILE_STAT mz_stat -#else #define MZ_FILE_STAT_STRUCT _stat64 -#define MZ_FILE_STAT mz_stat64 -#endif +#define MZ_FILE_STAT _stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove - -#elif defined(__WATCOMC__) +#elif defined(__MINGW32__) #ifndef MINIZ_NO_TIME #include #endif @@ -2758,14 +2647,13 @@ static int mz_stat64(const char* path, struct __stat64* buffer) { #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite -#define MZ_FTELL64 _ftelli64 -#define MZ_FSEEK64 _fseeki64 -#define MZ_FILE_STAT_STRUCT stat -#define MZ_FILE_STAT stat +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove - #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include @@ -2781,7 +2669,6 @@ static int mz_stat64(const char* path, struct __stat64* buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove - #elif defined(__USE_LARGEFILE64) /* gcc, clang */ #ifndef MINIZ_NO_TIME #include @@ -2797,8 +2684,7 @@ static int mz_stat64(const char* path, struct __stat64* buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove - -#elif defined(__APPLE__) || defined(__FreeBSD__) || (defined(__linux__) && defined(__x86_64__)) +#elif defined(__APPLE__) #ifndef MINIZ_NO_TIME #include #endif @@ -2942,7 +2828,7 @@ struct mz_zip_internal_state_tag { mz_zip_array m_sorted_central_dir_offsets; /* The flags passed in when the archive is initially opened. */ - mz_uint32 m_init_flags; + uint32_t m_init_flags; /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ mz_bool m_zip64; @@ -3230,8 +3116,7 @@ static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive* pZip, mz_uint32 r } /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= ((mz_uint64)(MZ_UINT16_MAX) + record_size))) - return MZ_FALSE; + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } @@ -3240,20 +3125,9 @@ static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive* pZip, mz_uint32 r return MZ_TRUE; } -static mz_bool mz_zip_reader_eocd64_valid(mz_zip_archive* pZip, uint64_t offset, uint8_t* buf) { - if (pZip->m_pRead(pZip->m_pIO_opaque, offset, buf, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { - if (MZ_READ_LE32(buf + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { - return MZ_TRUE; - } - } - - return MZ_FALSE; -} - static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; - mz_uint64 cdir_ofs = 0, eocd_ofs = 0, archive_ofs = 0; + mz_uint64 cdir_ofs = 0; mz_int64 cur_file_ofs = 0; const mz_uint8* p; @@ -3279,7 +3153,6 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint flag MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); - eocd_ofs = cur_file_ofs; /* Read and verify the end of central directory record. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) @@ -3292,32 +3165,21 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint flag if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) { if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) { - pZip->m_pState->m_zip64 = MZ_TRUE; + zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { + if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { + pZip->m_pState->m_zip64 = MZ_TRUE; + } + } } } } - if (pZip->m_pState->m_zip64) { - /* Try locating the EOCD64 right before the EOCD64 locator. This works even - * when the effective start of the zip header is not yet known. */ - if (cur_file_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - zip64_end_of_central_dir_ofs = - cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; - - if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir)) { - /* That failed, try reading where the locator tells us to. */ - zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); - - if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir)) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - } - } - pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); @@ -3365,32 +3227,12 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint flag if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); - if (cdir_size < (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - if (eocd_ofs < cdir_ofs + cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - /* The end of central dir follows the central dir, unless the zip file has - * some trailing data (e.g. it is appended to an executable file). */ - archive_ofs = eocd_ofs - (cdir_ofs + cdir_size); - if (pZip->m_pState->m_zip64) { - if (archive_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - - archive_ofs -= MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; - } - - /* Update the archive start position, but only if not specified. */ - if ((pZip->m_zip_type == MZ_ZIP_TYPE_FILE || pZip->m_zip_type == MZ_ZIP_TYPE_CFILE || - pZip->m_zip_type == MZ_ZIP_TYPE_USER) && - pZip->m_pState->m_file_archive_start_ofs == 0) { - pZip->m_pState->m_file_archive_start_ofs = archive_ofs; - pZip->m_archive_size -= archive_ofs; - } - pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { @@ -3522,7 +3364,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive* pZip, mz_uint flag } void mz_zip_zero_struct(mz_zip_archive* pZip) { - if (pZip) MZ_CLEAR_PTR(pZip); + if (pZip) MZ_CLEAR_OBJ(*pZip); } static mz_bool mz_zip_reader_end_internal(mz_zip_archive* pZip, mz_bool set_last_error) { @@ -3642,7 +3484,7 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive* pZip, const char* pFilename, if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_READ_ALLOW_WRITING) ? "r+b" : "rb"); + pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); file_size = archive_size; @@ -3942,7 +3784,7 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive* pZip, const char const mz_zip_array* pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array* pCentral_dir = &pState->m_central_dir; mz_uint32* pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); - const mz_uint32 size = pZip->m_total_files; + const uint32_t size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); if (pIndex) *pIndex = 0; @@ -3954,7 +3796,7 @@ static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive* pZip, const char while (l <= h) { mz_int64 m = l + ((h - l) >> 1); - mz_uint32 file_index = pIndices[(mz_uint32)m]; + uint32_t file_index = pIndices[(uint32_t)m]; int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) { @@ -4034,9 +3876,8 @@ mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive* pZip, const char* pName, co return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } -static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, - size_t buf_size, mz_uint flags, void* pUser_read_buf, - size_t user_read_buf_size, const mz_zip_archive_file_stat* st) { +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, + mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; @@ -4049,10 +3890,7 @@ static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive* pZip, mz_u (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - if (st) { - file_stat = *st; - } else if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) - return MZ_FALSE; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; @@ -4080,8 +3918,7 @@ static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive* pZip, mz_u if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + - MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); @@ -4172,24 +4009,18 @@ static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(mz_zip_archive* pZip, mz_u return status == TINFL_STATUS_DONE; } -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, - mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size) { - return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, - user_read_buf_size, NULL); -} - mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, - user_read_buf_size, NULL); + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, + user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, mz_uint flags) { - return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, buf_size, flags, NULL, 0, NULL); + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, @@ -4198,15 +4029,21 @@ mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFil } void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags) { - mz_zip_archive_file_stat file_stat; - mz_uint64 alloc_size; + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8* p = mz_zip_get_cdh(pZip, file_index); void* pBuf; if (pSize) *pSize = 0; - if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return NULL; + if (!p) { + mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); + return NULL; + } - alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); return NULL; @@ -4217,7 +4054,7 @@ void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, si return NULL; } - if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf, (size_t)alloc_size, flags, NULL, 0, &file_stat)) { + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } @@ -4276,8 +4113,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_ind if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + - MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); @@ -4489,8 +4325,7 @@ mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive* return NULL; } - pState->cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + - MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); @@ -4626,7 +4461,7 @@ size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, size_t to_copy = MZ_MIN((buf_size - copied_to_caller), pState->out_blk_remain); /* Copy data to caller's buffer */ - memcpy((mz_uint8*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy); + memcpy((uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Perform CRC */ @@ -4963,7 +4798,7 @@ handle_failure: mz_bool mz_zip_validate_archive(mz_zip_archive* pZip, mz_uint flags) { mz_zip_internal_state* pState; - mz_uint32 i; + uint32_t i; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); @@ -4976,6 +4811,8 @@ mz_bool mz_zip_validate_archive(mz_zip_archive* pZip, mz_uint flags) { if (pZip->m_archive_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } else { + if (pZip->m_total_files >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); + if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } @@ -5280,7 +5117,7 @@ mz_bool mz_zip_writer_init_file_v2(mz_zip_archive* pZip, const char* pFilename, mz_uint64 cur_ofs = 0; char buf[4096]; - MZ_CLEAR_ARR(buf); + MZ_CLEAR_OBJ(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); @@ -5345,7 +5182,7 @@ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive* pZip, const char* pFil #else if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE && !(flags & MZ_ZIP_FLAG_READ_ALLOW_WRITING)) { + if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (!pFilename) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ @@ -5613,7 +5450,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive* pZip, const char* pArchive_n pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } - if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } @@ -5632,8 +5469,6 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive* pZip, const char* pArchive_n time(&cur_time); mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } -#else - (void)last_modified; #endif /* #ifndef MINIZ_NO_TIME */ if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { @@ -5698,7 +5533,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive* pZip, const char* pArchive_n } cur_archive_file_ofs += num_alignment_padding_bytes; - MZ_CLEAR_ARR(local_dir_header); + MZ_CLEAR_OBJ(local_dir_header); if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { method = MZ_DEFLATED; @@ -5847,7 +5682,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive* pZip, const char* pA mz_uint level_and_flags, 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 gen_flags; + mz_uint16 gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) ? 0 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; @@ -5859,13 +5694,11 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive* pZip, const char* pA mz_zip_internal_state* pState; mz_uint64 file_ofs = 0, cur_archive_header_file_ofs; + if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; - gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) ? 0 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; - - if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; - /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) @@ -5918,8 +5751,6 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive* pZip, const char* pA if (pFile_time) { mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); } -#else - (void)pFile_time; #endif if (max_size <= 3) level = 0; @@ -5939,7 +5770,7 @@ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive* pZip, const char* pA method = MZ_DEFLATED; } - MZ_CLEAR_ARR(local_dir_header); + MZ_CLEAR_OBJ(local_dir_header); if (pState->m_zip64) { if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; @@ -6228,9 +6059,9 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, #endif /* #ifndef MINIZ_NO_STDIO */ static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array* pNew_ext, mz_zip_archive* pZip, - const mz_uint8* pExt, mz_uint32 ext_len, - mz_uint64* pComp_size, mz_uint64* pUncomp_size, - mz_uint64* pLocal_header_ofs, mz_uint32* pDisk_start) { + const mz_uint8* pExt, uint32_t ext_len, mz_uint64* pComp_size, + mz_uint64* pUncomp_size, mz_uint64* pLocal_header_ofs, + mz_uint32* pDisk_start) { /* + 64 should be enough for any new zip64 data */ if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); @@ -6374,7 +6205,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); - src_archive_bytes_remaining = src_file_stat.m_comp_size + local_header_filename_size + local_header_extra_len; + src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; /* Try to find a zip64 extended information field */ if ((local_header_extra_len) && @@ -6525,10 +6356,10 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* if (pZip->m_pState->m_zip64) { /* dest is zip64, so upgrade the data descriptor */ - const mz_uint8* pSrc_descriptor = (const mz_uint8*)pBuf + (has_id ? sizeof(mz_uint32) : 0); - const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor); - const mz_uint64 src_comp_size = MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32)); - const mz_uint64 src_uncomp_size = MZ_READ_LE32(pSrc_descriptor + 2 * sizeof(mz_uint32)); + const mz_uint32* pSrc_descriptor = (const mz_uint32*)((const mz_uint8*)pBuf + (has_id ? sizeof(mz_uint32) : 0)); + const mz_uint32 src_crc32 = pSrc_descriptor[0]; + const mz_uint64 src_comp_size = pSrc_descriptor[1]; + const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; mz_write_le32((mz_uint8*)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); mz_write_le32((mz_uint8*)pBuf + sizeof(mz_uint32) * 1, src_crc32); @@ -6653,7 +6484,8 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip) { pState = pZip->m_pState; if (pState->m_zip64) { - if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); + if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) + return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) @@ -6678,7 +6510,7 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip) { /* Write zip64 end of central directory header */ mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; - MZ_CLEAR_ARR(hdr); + MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); @@ -6695,7 +6527,7 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip) { pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; /* Write zip64 end of central directory locator */ - MZ_CLEAR_ARR(hdr); + MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); @@ -6707,7 +6539,7 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip) { } /* Write end of central directory record */ - MZ_CLEAR_ARR(hdr); + MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); @@ -6794,15 +6626,13 @@ mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char* pZip_filename, co created_new_archive = MZ_TRUE; } else { /* Append to an existing archive. */ - if (!mz_zip_reader_init_file_v2( - &zip_archive, pZip_filename, - level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY | MZ_ZIP_FLAG_READ_ALLOW_WRITING, 0, 0)) { + if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, + level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } - if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, - level_and_flags | MZ_ZIP_FLAG_READ_ALLOW_WRITING)) { + if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); @@ -6983,9 +6813,7 @@ const char* mz_zip_get_error_string(mz_zip_error mz_err) { case MZ_ZIP_VALIDATION_FAILED: return "validation failed"; case MZ_ZIP_WRITE_CALLBACK_FAILED: - return "write callback failed"; - case MZ_ZIP_TOTAL_ERRORS: - return "total errors"; + return "write calledback failed"; default: break; } diff --git a/lib/miniz/miniz.h b/lib/miniz/miniz.h index 57e2f36..68d0013 100644 --- a/lib/miniz/miniz.h +++ b/lib/miniz/miniz.h @@ -1,201 +1,150 @@ -#ifndef MINIZ_EXPORT #define MINIZ_EXPORT -#endif -/* miniz.c 3.1.0 - public domain deflate/inflate, zlib-subset, ZIP - reading/writing/appending, PNG writing See "unlicense" statement at the end - of this file. Rich Geldreich , last updated Oct. 13, - 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: - http://www.ietf.org/rfc/rfc1951.txt +/* miniz.c 2.2.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt - Most API's defined in miniz.c are optional. For example, to disable the - archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of - all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Low-level Deflate/Inflate implementation notes: - Compression: Use the "tdefl" API's. The compressor supports raw, static, - and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, - and Huffman-only streams. It performs and compresses approximately as well as - zlib. + Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses + approximately as well as zlib. - Decompression: Use the "tinfl" API's. The entire decompressor is - implemented as a single function coroutine: see tinfl_decompress(). It - supports decompression into a 32KB (or larger power of 2) wrapping buffer, or + Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. - The low-level tdefl/tinfl API's do not make any use of dynamic memory - allocation. + The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: - miniz.c implements a fairly large subset of zlib. There's enough - functionality present for it to be a drop-in zlib replacement in many apps: + miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in + zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateReset/inflateEnd compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly - routines. Supports raw deflate streams or standard zlib streams with adler-32 - checking. + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. + Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: - The callback API's are not implemented yet. No support for gzip headers or - zlib static dictionaries. I've tried to closely emulate zlib's various - flavors of stream flushing and return status codes, but there are no - guarantees that miniz.c pulls this off perfectly. + The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, - originally written by Alex Evans. Supports 1-4 bytes/pixel images. + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by + Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: - The ZIP archive API's where designed with simplicity and efficiency in - mind, with just enough abstraction to get the job done with minimal fuss. - There are simple API's to retrieve file information, read files from existing - archives, create new archives, append new files to existing archives, or - clone archive data from one archive to another. It supports archives located - in memory or the heap, on disk (using stdio.h), or you can specify custom - file read/write callbacks. + The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file information, read files from + existing archives, create new archives, append new files to existing archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), + or you can specify custom file read/write callbacks. - - Archive reading: Just call this function to read a single file from a - disk archive: + - Archive reading: Just call this function to read a single file from a disk archive: - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const - char *pArchive_name, size_t *pSize, mz_uint zip_flags); + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); - For more complex cases, use the "mz_zip_reader" functions. Upon opening an - archive, the entire central directory is located and read as-is into memory, - and subsequent file access only occurs when reading individual files. + For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central + directory is located and read as-is into memory, and subsequent file access only occurs when reading individual + files. - - Archives file scanning: The simple way is to use this function to scan a - loaded archive for a specific file: + - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, - const char *pComment, mz_uint flags); + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); - The locate operation can optionally check file comments too, which (as one - example) can be used to identify multiple versions of the same file in an - archive. This function uses a simple linear search through the central + The locate operation can optionally check file comments too, which (as one example) can be used to identify + multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. - Alternately, you can iterate through all the files in an archive (using - mz_zip_reader_get_num_files()) and retrieve detailed info on each file by - calling mz_zip_reader_file_stat(). + Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer - immediately writes compressed file data to disk and builds an exact image of - the central directory in memory. The central directory image is written all - at once at the end of the archive file when the archive is finalized. + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The central directory image is written + all at once at the end of the archive file when the archive is finalized. - The archive writer can optionally align each file's local header and file - data to any power of 2 alignment, which can be useful when the archive will - be read from optical media. Also, the writer supports placing arbitrary data - blobs at the very beginning of ZIP archives. Archives written using either - feature are still readable by any ZIP tool. + The archive writer can optionally align each file's local header and file data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still + readable by any ZIP tool. - - Archive appending: The simple way to add a single file to an archive is - to call this function: + - Archive appending: The simple way to add a single file to an archive is to call this function: - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, - const char *pArchive_name, const void *pBuf, size_t buf_size, const void - *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - The archive will be created if it doesn't already exist, otherwise it'll be - appended to. Note the appending is done in-place and is not an atomic - operation, so if something goes wrong during the operation it's possible the - archive could be left without a central directory (although the local file - headers and file data will be fine, so the archive will be recoverable). + The archive will be created if it doesn't already exist, otherwise it'll be appended to. + Note the appending is done in-place and is not an atomic operation, so if something goes wrong + during the operation it's possible the archive could be left without a central directory (although the local + file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, - cloning only those bits you want to preserve into a new archive using using - the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and - rename the newly written archive, and you're done. This is safe but requires - a bunch of temporary disk space or heap memory. + 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to + preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or heap memory. - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using - mz_zip_writer_init_from_reader(), append new files as needed, then finalize - the archive which will write an updated central directory to the original - archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() - does.) There's a possibility that the archive's central directory could be - lost with this method if anything goes wrong, though. + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an updated central directory to the + original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: - No spanning support. Extraction functions can only handle unencrypted, - stored or deflated files. Requires streams capable of seeking. + No spanning support. Extraction functions can only handle unencrypted, stored or deflated files. + Requires streams capable of seeking. - * This is a header file library, like stb_image.c. To get only a header file, - either cut and paste the below header, or create miniz.h, #define - MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - * Important: For best perf. be sure to customize the below macros for your - target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define - MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 + * Important: For best perf. be sure to customize the below macros for your target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before - including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), - stat64(), etc. Otherwise you won't be able to process large files (i.e. - 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #pragma once /* Defines to completely disable specific portions of miniz.c: - If all macros here are defined the only functionality remaining will be - CRC-32 and adler-32. */ + If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ -/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on - * stdio for file I/O. */ +/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ /*#define MINIZ_NO_STDIO */ -/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able - * to get the current time, or */ -/* get/set file times, and the C run-time funcs that get/set times won't be - * called. */ -/* The current downside is the times written to your archives will be from 1979. - */ +/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ +/* get/set file times, and the C run-time funcs that get/set times won't be called. */ +/* The current downside is the times written to your archives will be from 1979. */ /*#define MINIZ_NO_TIME */ -/* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */ -/*#define MINIZ_NO_DEFLATE_APIS */ - -/* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */ -/*#define MINIZ_NO_INFLATE_APIS */ - /* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_APIS */ -/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP - * archive API's. */ +/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ /*#define MINIZ_NO_ARCHIVE_WRITING_APIS */ -/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression - * API's. */ +/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ /*#define MINIZ_NO_ZLIB_APIS */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent - * conflicts against stock zlib. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ /*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ /* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. - Note if MINIZ_NO_MALLOC is defined then the user must always provide custom - user alloc/free/realloc callbacks to the zlib and archive API's, and a few - stand-alone helper API's which don't provide custom user functions (such as - tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. - */ + Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc + callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user + functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ /*#define MINIZ_NO_MALLOC */ -#ifdef MINIZ_NO_INFLATE_APIS -#define MINIZ_NO_ARCHIVE_APIS -#endif - -#ifdef MINIZ_NO_DEFLATE_APIS -#define MINIZ_NO_ARCHIVE_WRITING_APIS -#endif - #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) -/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc - * on Linux */ +/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ #define MINIZ_NO_TIME #endif @@ -213,41 +162,19 @@ #define MINIZ_X86_OR_X64_CPU 0 #endif -/* Set MINIZ_LITTLE_ENDIAN only if not set */ -#if !defined(MINIZ_LITTLE_ENDIAN) -#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif -#else - -#if MINIZ_X86_OR_X64_CPU -#define MINIZ_LITTLE_ENDIAN 1 -#else -#define MINIZ_LITTLE_ENDIAN 0 -#endif - -#endif -#endif - -/* Using unaligned loads and stores causes errors when using UBSan */ -#if defined(__has_feature) -#if __has_feature(undefined_behavior_sanitizer) -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 -#endif -#endif - /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) #if MINIZ_X86_OR_X64_CPU -/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient - * integer loads and stores from unaligned addresses. */ -#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned + * addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_UNALIGNED_USE_MEMCPY #else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 @@ -256,9 +183,8 @@ #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || \ defined(__ia64__) || defined(__x86_64__) -/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are - * reasonably fast (and don't involve compiler generated calls to helper - * functions). */ +/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler + * generated calls to helper functions). */ #define MINIZ_HAS_64BIT_REGISTERS 1 #else #define MINIZ_HAS_64BIT_REGISTERS 0 @@ -270,23 +196,20 @@ extern "C" { /* ------------------- zlib-style API Definitions. */ -/* For more compatibility with zlib, miniz.c uses unsigned long for some - * parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ +/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can + * be either 32 or 64-bits! */ typedef unsigned long mz_ulong; -/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() - * unless you've modified the MZ_MALLOC macro) to release a block allocated from - * the heap. */ +/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC + * macro) to release a block allocated from the heap. */ MINIZ_EXPORT void mz_free(void* p); #define MZ_ADLER32_INIT (1) -/* mz_adler32() returns the initial adler-32 value to use when called with - * ptr==NULL. */ +/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len); #define MZ_CRC32_INIT (0) -/* mz_crc32() returns the initial CRC-32 value to use when called with - * ptr==NULL. */ +/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char* ptr, size_t buf_len); /* Compression strategies. */ @@ -296,15 +219,13 @@ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3 #define MZ_DEFLATED 8 /* Heap allocation callbacks. -Note that mz_alloc_func parameter types purposely differ from zlib's: items/size -is size_t, not unsigned long. */ +Note that mz_alloc_func parameter types purposely differ from zlib's: items/size is size_t, not unsigned long. */ typedef void* (*mz_alloc_func)(void* opaque, size_t items, size_t size); typedef void (*mz_free_func)(void* opaque, void* address); typedef void* (*mz_realloc_func)(void* opaque, void* address, size_t items, size_t size); -/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best - * possible compression (not zlib compatible, and may be very slow), - * MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ +/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and + * may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, @@ -314,17 +235,17 @@ enum { MZ_DEFAULT_COMPRESSION = -1 }; -#define MZ_VERSION "11.3.0" -#define MZ_VERNUM 0xB300 -#define MZ_VER_MAJOR 11 -#define MZ_VER_MINOR 3 +#define MZ_VERSION "10.2.0" +#define MZ_VERNUM 0xA100 +#define MZ_VER_MAJOR 10 +#define MZ_VER_MINOR 2 #define MZ_VER_REVISION 0 #define MZ_VER_SUBREVISION 0 #ifndef MINIZ_NO_ZLIB_APIS -/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The - * other values are for advanced use (refer to the zlib docs). */ +/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer + * to the zlib docs). */ enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; /* Return status codes. MZ_PARAM_ERROR is non-standard. */ @@ -373,16 +294,14 @@ typedef mz_stream* mz_streamp; /* Returns the version string of miniz.c. */ MINIZ_EXPORT const char* mz_version(void); -#ifndef MINIZ_NO_DEFLATE_APIS - /* mz_deflateInit() initializes a compressor with default options: */ /* Parameters: */ /* pStream must point to an initialized mz_stream struct. */ /* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ -/* level 1 enables a specially optimized compression function that's been - * optimized purely for performance, not ratio. */ -/* (This special func. is currently only enabled when - * MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ +/* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. + */ +/* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are + * defined.) */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ @@ -393,35 +312,31 @@ MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level); /* mz_deflateInit2() is like mz_deflate(), except with more control: */ /* Additional parameters: */ /* method must be MZ_DEFLATED */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with - * zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no - * header or footer) */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or + * -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ /* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); -/* Quickly resets a compressor without having to reallocate anything. Same as - * calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by + * mz_deflateInit()/mz_deflateInit2(). */ MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream); -/* mz_deflate() compresses the input to output, consuming as much of the input - * and producing as much output as possible. */ +/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. + */ /* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update - * the next_in, avail_in, next_out, and avail_out members. */ -/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or - * MZ_FINISH. */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and + * avail_out members. */ +/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ /* Return values: */ -/* MZ_OK on success (when flushing, or if more input is needed but not - * available, and/or there's more output to be written but the output buffer is - * full). */ -/* MZ_STREAM_END if all input has been consumed and all output bytes have been - * written. Don't call mz_deflate() on the stream anymore. */ +/* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be + * written but the output buffer is full). */ +/* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the + * stream anymore. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input and/or - * output buffers are empty. (Fill up the input buffer or free up some output - * space and try again.) */ +/* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the + * input buffer or free up some output space and try again.) */ MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); /* mz_deflateEnd() deinitializes a compressor: */ @@ -430,89 +345,73 @@ MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush); /* MZ_STREAM_ERROR if the stream is bogus. */ MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream); -/* mz_deflateBound() returns a (very) conservative upper bound on the amount of - * data that could be generated by deflate(), assuming flush is set to only - * MZ_NO_FLUSH or MZ_FINISH. */ +/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by + * deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); /* Single-call compression functions mz_compress() and mz_compress2(): */ -/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on - * failure. */ +/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ MINIZ_EXPORT int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len); MINIZ_EXPORT int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len, int level); -/* mz_compressBound() returns a (very) conservative upper bound on the amount of - * data that could be generated by calling mz_compress(). */ +/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling + * mz_compress(). */ MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len); -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - -#ifndef MINIZ_NO_INFLATE_APIS - /* Initializes a decompressor. */ MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream); -/* mz_inflateInit2() is like mz_inflateInit() with an additional option that - * controls the window size and whether or not the stream has been wrapped with - * a zlib header/footer: */ -/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or - * -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ +/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not + * the stream has been wrapped with a zlib header/footer: */ +/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits); -/* Quickly resets a compressor without having to reallocate anything. Same as - * calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ +/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by + * mz_inflateInit()/mz_inflateInit2(). */ MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream); -/* Decompresses the input stream to the output, consuming only as much of the - * input as needed, and writing as much to the output as possible. */ +/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to + * the output as possible. */ /* Parameters: */ -/* pStream is the stream to read from and write to. You must initialize/update - * the next_in, avail_in, next_out, and avail_out members. */ +/* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and + * avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ -/* On the first call, if flush is MZ_FINISH it's assumed the input and output - * buffers are both sized large enough to decompress the entire stream in a - * single call (this is slightly faster). */ -/* MZ_FINISH implies that there are no more source bytes available beside - * what's already in the input buffer, and that the output buffer is large - * enough to hold the rest of the decompressed data. */ +/* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to + * decompress the entire stream in a single call (this is slightly faster). */ +/* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that + * the output buffer is large enough to hold the rest of the decompressed data. */ /* Return values: */ -/* MZ_OK on success. Either more input is needed but not available, and/or - * there's more output to be written but the output buffer is full. */ -/* MZ_STREAM_END if all needed input has been consumed and all output bytes - * have been written. For zlib streams, the adler-32 of the decompressed data - * has also been verified. */ +/* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the + * output buffer is full. */ +/* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the + * adler-32 of the decompressed data has also been verified. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_DATA_ERROR if the deflate stream is invalid. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ -/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is - * empty but the inflater needs more input to continue, or if the output buffer - * is not large enough. Call mz_inflate() again */ -/* with more input data, or with more room in the output buffer (except when - * using single call decompression, described above). */ +/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input + * to continue, or if the output buffer is not large enough. Call mz_inflate() again */ +/* with more input data, or with more room in the output buffer (except when using single call decompression, + * described above). */ MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush); /* Deinitializes a decompressor. */ MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream); /* Single-call decompression. */ -/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on - * failure. */ +/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ MINIZ_EXPORT int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len); MINIZ_EXPORT int mz_uncompress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong* pSource_len); -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ -/* Returns a string description of the specified error code, or NULL if the - * error code is invalid. */ +/* Returns a string description of the specified error code, or NULL if the error code is invalid. */ MINIZ_EXPORT const char* mz_error(int err); -/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used - * as a drop-in replacement for the subset of zlib that miniz.c supports. */ -/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you - * use zlib in the same project. */ +/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset + * of zlib that miniz.c supports. */ +/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; @@ -553,72 +452,37 @@ typedef void* const voidpc; #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS -/* See mz_alloc_func */ -typedef void* (*alloc_func)(void* opaque, size_t items, size_t size); -/* See mz_free_func */ -typedef void (*free_func)(void* opaque, void* address); - +#define alloc_func mz_alloc_func +#define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream - -#ifndef MINIZ_NO_DEFLATE_APIS -/* Compatiblity with zlib API. See called functions for documentation */ -static int deflateInit(mz_streamp pStream, int level) { return mz_deflateInit(pStream, level); } -static int deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { - return mz_deflateInit2(pStream, level, method, window_bits, mem_level, strategy); -} -static int deflateReset(mz_streamp pStream) { return mz_deflateReset(pStream); } -static int deflate(mz_streamp pStream, int flush) { return mz_deflate(pStream, flush); } -static int deflateEnd(mz_streamp pStream) { return mz_deflateEnd(pStream); } -static mz_ulong deflateBound(mz_streamp pStream, mz_ulong source_len) { return mz_deflateBound(pStream, source_len); } -static int compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len) { - return mz_compress(pDest, pDest_len, pSource, source_len); -} -static int compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len, - int level) { - return mz_compress2(pDest, pDest_len, pSource, source_len, level); -} -static mz_ulong compressBound(mz_ulong source_len) { return mz_compressBound(source_len); } -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ - -#ifndef MINIZ_NO_INFLATE_APIS -/* Compatiblity with zlib API. See called functions for documentation */ -static int inflateInit(mz_streamp pStream) { return mz_inflateInit(pStream); } - -static int inflateInit2(mz_streamp pStream, int window_bits) { return mz_inflateInit2(pStream, window_bits); } - -static int inflateReset(mz_streamp pStream) { return mz_inflateReset(pStream); } - -static int inflate(mz_streamp pStream, int flush) { return mz_inflate(pStream, flush); } - -static int inflateEnd(mz_streamp pStream) { return mz_inflateEnd(pStream); } - -static int uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len) { - return mz_uncompress(pDest, pDest_len, pSource, source_len); -} - -static int uncompress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong* pSource_len) { - return mz_uncompress2(pDest, pDest_len, pSource, pSource_len); -} -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - -static mz_ulong crc32(mz_ulong crc, const unsigned char* ptr, size_t buf_len) { return mz_crc32(crc, ptr, buf_len); } - -static mz_ulong adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len) { - return mz_adler32(adler, ptr, buf_len); -} - +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflateReset mz_inflateReset +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define uncompress2 mz_uncompress2 +#define crc32 mz_crc32 +#define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 - -static const char* zError(int err) { return mz_error(err); } +#define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION - #define zlibVersion mz_version #define zlib_version mz_version() #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ @@ -637,10 +501,10 @@ static const char* zError(int err) { return mz_error(err); } /* ------------------- Types and macros */ typedef unsigned char mz_uint8; -typedef int16_t mz_int16; -typedef uint16_t mz_uint16; -typedef uint32_t mz_uint32; -typedef uint32_t mz_uint; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; typedef int64_t mz_int64; typedef uint64_t mz_uint64; typedef int mz_bool; @@ -648,8 +512,7 @@ typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) -/* Works around MSVC's spammy "warning C4127: conditional expression is - * constant" message. */ +/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else @@ -665,8 +528,7 @@ typedef int mz_bool; #ifdef MINIZ_NO_TIME typedef struct mz_dummy_time_t_tag { - mz_uint32 m_dummy1; - mz_uint32 m_dummy2; + int m_dummy; } mz_dummy_time_t; #define MZ_TIME_T mz_dummy_time_t #else @@ -688,8 +550,6 @@ typedef struct mz_dummy_time_t_tag { #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) -#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj)) -#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16*)(p)) @@ -728,43 +588,33 @@ extern MINIZ_EXPORT void* miniz_def_realloc_func(void* opaque, void* address, si #endif #pragma once -#ifndef MINIZ_NO_DEFLATE_APIS - #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression API Definitions */ -/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly - * slower, and raw/dynamic blocks will be output more frequently). */ -#ifndef TDEFL_LESS_MEMORY +/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be + * output more frequently). */ #define TDEFL_LESS_MEMORY 0 -#endif -/* tdefl_init() compression flags logically OR'd together (low 12 bits contain - * the max. number of probes per dictionary search): */ -/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes - * per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap - * compression), 4095=Huffman+LZ (slowest/best compression). */ +/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary + * search): */ +/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, + * 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; -/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before - * the deflate data, and the Adler-32 of the source data at the end. Otherwise, - * you'll get raw deflate data. */ -/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even - * when not writing zlib headers). */ -/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more - * efficient lazy parsing. */ -/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's - * initialization time to the minimum, but the output may vary from run to run - * given the same input (depending on the contents of memory). */ -/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) - */ +/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of + * the source data at the end. Otherwise, you'll get raw deflate data. */ +/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ +/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ +/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the + * output may vary from run to run given the same input (depending on the contents of memory). */ +/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ /* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ /* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ /* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ -/* The low 12 bits are reserved to control the max # of hash probes per - * dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ +/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). + */ enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, @@ -777,51 +627,47 @@ enum { }; /* High level compression functions: */ -/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block - * allocated via malloc(). */ +/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ -/* flags: The max match finder probes (default is 128) logically OR'd against - * the above flags. Higher probes are slower but improve compression. */ +/* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower + * but improve compression. */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ -/* *pOut_len will be set to the compressed data's size, which could be larger - * than src_buf_len on uncompressible data. */ +/* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. + */ /* The caller must free() the returned block when it's no longer needed. */ MINIZ_EXPORT void* tdefl_compress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags); -/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in - * memory. */ +/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ /* Returns 0 on failure. */ MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, int flags); /* Compresses an image to a compressed PNG file in memory. */ /* On entry: */ -/* pImage, w, h, and num_chans describe the image to compress. num_chans may be - * 1, 2, 3, or 4. */ -/* The image pitch in bytes per scanline will be w*num_chans. The leftmost - * pixel on the top scanline is stored first in memory. */ -/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, - * MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ -/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL - * apps). */ +/* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ +/* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in + * memory. */ +/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is + * MZ_DEFAULT_LEVEL */ +/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pLen_out will be set to the size of the PNG image file. */ -/* The caller must mz_free() the returned heap block (which will typically be - * larger than *pLen_out) when it's no longer needed. */ +/* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no + * longer needed. */ MINIZ_EXPORT void* tdefl_write_image_to_png_file_in_memory_ex(const void* pImage, int w, int h, int num_chans, size_t* pLen_out, mz_uint level, mz_bool flip); MINIZ_EXPORT void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, int num_chans, size_t* pLen_out); -/* Output stream interface. The compressor uses this interface to write - * compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ +/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called + * TDEFL_OUT_BUF_SIZE at a time. */ typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser); -/* tdefl_compress_mem_to_output() compresses a block to an output stream. The - * above helpers use this function internally. */ +/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function + * internally. */ MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output(const void* pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags); @@ -836,8 +682,8 @@ enum { TDEFL_MAX_MATCH_LEN = 258 }; -/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed - * output block (using static/fixed Huffman codes). */ +/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman + * codes). */ #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, @@ -851,7 +697,7 @@ enum { #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, - TDEFL_OUT_BUF_SIZE = (mz_uint)((TDEFL_LZ_CODE_BUF_SIZE * 13) / 10), + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, @@ -860,9 +706,8 @@ enum { }; #endif -/* The low-level tdefl functions below may be used directly if the above helper - * functions aren't flexible enough. The low-level functions don't make any heap - * allocations, unlike the above helper functions. */ +/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The + * low-level functions don't make any heap allocations, unlike the above helper functions. */ typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, @@ -902,26 +747,20 @@ typedef struct { } tdefl_compressor; /* Initializes the compressor. */ -/* There is no corresponding deinit() function because the tdefl API's do not - * dynamically allocate memory. */ -/* pBut_buf_func: If NULL, output data will be supplied to the specified - * callback. In this case, the user should call the tdefl_compress_buffer() API - * for compression. */ -/* If pBut_buf_func is NULL the user should always call the tdefl_compress() - * API. */ -/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, - * etc.) */ +/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ +/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call + * the tdefl_compress_buffer() API for compression. */ +/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ +/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags); -/* Compresses a block of data, consuming as much of the specified input buffer - * as possible, and writing as much compressed data to the specified output - * buffer as possible. */ +/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much + * compressed data to the specified output buffer as possible. */ MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pIn_buf_size, void* pOut_buf, size_t* pOut_buf_size, tdefl_flush flush); -/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a - * non-NULL tdefl_put_buf_func_ptr. */ +/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ /* tdefl_compress_buffer() always consumes the entire input buffer. */ MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor* d, const void* pIn_buf, size_t in_buf_size, tdefl_flush flush); @@ -930,11 +769,9 @@ MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor* d); MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor* d); /* Create tdefl_compress() flags given zlib-style compression parameters. */ -/* level may range from [0,10] (where 10 is absolute max compression, but may be - * much slower on some files) */ +/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ /* window_bits may be -15 (raw deflate) or 15 (zlib) */ -/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, - * MZ_RLE, or MZ_FIXED */ +/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); #ifndef MINIZ_NO_MALLOC @@ -948,29 +785,21 @@ MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor* pComp); #ifdef __cplusplus } #endif - -#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/ #pragma once /* ------------------- Low-level Decompression API Definitions */ -#ifndef MINIZ_NO_INFLATE_APIS - #ifdef __cplusplus extern "C" { #endif /* Decompression flags used by tinfl_decompress(). */ -/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and - * ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the - * input is a raw deflate stream. */ -/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available - * beyond the end of the supplied input buffer. If clear, the input buffer - * contains all remaining input. */ -/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large - * enough to hold the entire decompressed stream. If clear, the output buffer is - * at least the size of the dictionary (typically 32KB). */ -/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the - * decompressed bytes. */ +/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a + * valid zlib stream). Otherwise, the input is a raw deflate stream. */ +/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. + * If clear, the input buffer contains all remaining input. */ +/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed + * stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ +/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, @@ -979,30 +808,24 @@ enum { }; /* High level decompression functions: */ -/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block - * allocated via malloc(). */ +/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ -/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data - * to decompress. */ +/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ /* On return: */ /* Function returns a pointer to the decompressed data, or NULL on failure. */ -/* *pOut_len will be set to the decompressed data's size, which could be larger - * than src_buf_len on uncompressible data. */ -/* The caller must call mz_free() on the returned block when it's no longer - * needed. */ +/* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible + * data. */ +/* The caller must call mz_free() on the returned block when it's no longer needed. */ MINIZ_EXPORT void* tinfl_decompress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags); -/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block - * in memory. */ -/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes - * written on success. */ +/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ +/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, int flags); -/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an - * internal 32KB buffer, and a user provided callback function will be called to - * flush the buffer. */ +/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided + * callback function will be called to flush the buffer. */ /* Returns 1 on success or 0 on failure. */ typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser); MINIZ_EXPORT int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, @@ -1024,59 +847,46 @@ MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor* pDecomp); /* Return status. */ typedef enum { - /* This flags indicates the inflator needs 1 or more input bytes to make - forward progress, but the caller is indicating that no more are available. - The compressed data */ - /* is probably corrupted. If you call the inflator again with more bytes it'll - try to continue processing the input but this is a BAD sign (either the - data is corrupted or you called it incorrectly). */ - /* If you call it again with no input you'll just get - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ + /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is + indicating that no more are available. The compressed data */ + /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input + but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ + /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, - /* This flag indicates that one or more of the input parameters was obviously - bogus. (You can try calling it again, but if you get this error the calling - code is wrong.) */ + /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, + but if you get this error the calling code is wrong.) */ TINFL_STATUS_BAD_PARAM = -3, - /* This flags indicate the inflator is finished but the adler32 check of the - uncompressed data didn't match. If you call it again it'll return - TINFL_STATUS_DONE. */ + /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you + call it again it'll return TINFL_STATUS_DONE. */ TINFL_STATUS_ADLER32_MISMATCH = -2, - /* This flags indicate the inflator has somehow failed (bad code, corrupted - input, etc.). If you call it again without resetting via tinfl_init() it - it'll just keep on returning the same status failure code. */ + /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without + resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ TINFL_STATUS_FAILED = -1, /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ - /* This flag indicates the inflator has returned every byte of uncompressed - data that it can, has consumed every byte that it needed, has successfully - reached the end of the deflate stream, and */ - /* if zlib headers and adler32 checking enabled that it has successfully - checked the uncompressed data's adler32. If you call it again you'll just - get TINFL_STATUS_DONE over and over again. */ + /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte + that it needed, has successfully reached the end of the deflate stream, and */ + /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If + you call it again you'll just get TINFL_STATUS_DONE over and over again. */ TINFL_STATUS_DONE = 0, - /* This flag indicates the inflator MUST have more input data (even 1 byte) - before it can make any more forward progress, or you need to clear the - TINFL_FLAG_HAS_MORE_INPUT */ - /* flag on the next call if you don't have any more source data. If the source - data was somehow corrupted it's also possible (but unlikely) for the - inflator to keep on demanding input to */ + /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward + progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ + /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also + possible (but unlikely) for the inflator to keep on demanding input to */ /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ TINFL_STATUS_NEEDS_MORE_INPUT = 1, - /* This flag indicates the inflator definitely has 1 or more bytes of - uncompressed data available, but it cannot write this data into the output - buffer. */ - /* Note if the source compressed data was corrupted it's possible for the - inflator to return a lot of uncompressed data to the caller. I've been - assuming you know how much uncompressed data to expect */ - /* (either exact or worst case) and will stop calling the inflator and fail - after receiving too much. In pure streaming scenarios where you have no - idea how many bytes to expect this may not be possible */ + /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write + this data into the output buffer. */ + /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed + data to the caller. I've been assuming you know how much uncompressed data to expect */ + /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure + streaming scenarios where you have no idea how many bytes to expect this may not be possible */ /* so I may need to add some code to address this. */ TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; @@ -1089,12 +899,10 @@ typedef enum { MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 -/* Main low-level decompressor coroutine function. This is the only function - * actually needed for decompression. All the other functions are just - * high-level helpers for improved usability. */ -/* This is a universal API, i.e. it can be used as a building block to build any - * desired higher level decompression API. In the limit case, it can be called - * once per every byte input or output. */ +/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the + * other functions are just high-level helpers for improved usability. */ +/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. + * In the limit case, it can be called once per every byte input or output. */ MINIZ_EXPORT tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size, mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size, const mz_uint32 decomp_flags); @@ -1109,6 +917,11 @@ enum { TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; +typedef struct { + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #else @@ -1128,13 +941,7 @@ struct tinfl_decompressor_tag { m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; - mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE]; - mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; - mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2]; - mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2]; - mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1]; - mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2]; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; @@ -1142,8 +949,6 @@ struct tinfl_decompressor_tag { } #endif -#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/ - #pragma once /* ------------------- ZIP archive reading/writing */ @@ -1155,8 +960,7 @@ extern "C" { #endif enum { - /* Note: These enums can be reduced as needed to save memory or stack space - - they are pretty conservative. */ + /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 @@ -1166,8 +970,8 @@ typedef struct { /* Central directory file index. */ mz_uint32 m_file_index; - /* Byte offset of this entry in the archive's central directory. Note we - * currently only support up to UINT_MAX or less bytes in the central dir. */ + /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less + * bytes in the central dir. */ mz_uint64 m_central_dir_ofs; /* These fields are copied directly from the zip's central dir. */ @@ -1176,15 +980,18 @@ typedef struct { mz_uint16 m_bit_flag; mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + MZ_TIME_T m_time; +#endif + /* CRC-32 of uncompressed data. */ mz_uint32 m_crc32; /* File's compressed size. */ mz_uint64 m_comp_size; - /* File's uncompressed size. Note, I've seen some old archives where directory - * entries had 512 bytes for their uncompressed sizes, but when you try to - * unpack them you actually get 0 bytes. */ + /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their + * uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ mz_uint64 m_uncomp_size; /* Zip internal and external file attributes. */ @@ -1200,12 +1007,10 @@ typedef struct { /* MZ_TRUE if the entry appears to be a directory. */ mz_bool m_is_directory; - /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip - * doesn't support) */ + /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ mz_bool m_is_encrypted; - /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a - * compression method we support. */ + /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ mz_bool m_is_supported; /* Filename. If string ends in '/' it's a subdirectory entry. */ @@ -1216,11 +1021,6 @@ typedef struct { /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; -#ifdef MINIZ_NO_TIME - MZ_TIME_T m_padding; -#else - MZ_TIME_T m_time; -#endif } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n); @@ -1242,20 +1042,18 @@ typedef enum { MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, - MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each - file as its validated to ensure the func finds the file in the - central dir (intended for testing) */ - MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire - file and check the crc32 */ - MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip - file format with automatic switch to zip64. Use as flags - parameter with mz_zip_writer_init*_v2 */ + MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = + 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func + finds the file in the central dir (intended for testing) */ + MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = + 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ + MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with + automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000, /*After adding a compressed file, seek back to local file header and set the correct sizes*/ - MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000, - MZ_ZIP_FLAG_READ_ALLOW_WRITING = 0x40000 + MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000 } mz_zip_flags; typedef enum { @@ -1268,8 +1066,7 @@ typedef enum { MZ_ZIP_TOTAL_TYPES } mz_zip_type; -/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or - * modify this enum. */ +/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ typedef enum { MZ_ZIP_NO_ERROR = 0, MZ_ZIP_UNDEFINED_ERROR, @@ -1337,7 +1134,9 @@ typedef struct { mz_uint flags; int status; - +#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS + mz_uint file_crc32; +#endif mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; mz_zip_archive_file_stat file_stat; void* pRead_buf; @@ -1347,12 +1146,6 @@ typedef struct { tinfl_decompressor inflator; -#ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS - mz_uint padding; -#else - mz_uint file_crc32; -#endif - } mz_zip_reader_extract_iter_state; /* -------- ZIP reading */ @@ -1366,31 +1159,28 @@ MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive* pZip, const void* pM #ifndef MINIZ_NO_STDIO /* Read a archive from a disk file. */ /* file_start_ofs is the file offset where the archive actually begins, or 0. */ -/* actual_archive_size is the true total size of the archive, which may be - * smaller than the file's actual size on disk. If zero the entire file is - * treated as the archive. */ +/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. + * If zero the entire file is treated as the archive. */ MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint32 flags); MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive* pZip, const char* pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); -/* Read an archive from an already opened FILE, beginning at the current file - * position. */ -/* The archive is assumed to be archive_size bytes long. If archive_size is 0, - * then the entire rest of the file is assumed to contain the archive. */ +/* Read an archive from an already opened FILE, beginning at the current file position. */ +/* The archive is assumed to be archive_size bytes long. If archive_size is 0, then the entire rest of the file is + * assumed to contain the archive. */ /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive* pZip, MZ_FILE* pFile, mz_uint64 archive_size, mz_uint flags); #endif -/* Ends archive reading, freeing all allocations, and closing the input archive - * file if mz_zip_reader_init_file() was used. */ +/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was + * used. */ MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive* pZip); /* -------- ZIP reading or writing */ /* Clears a mz_zip_archive struct to all zeros. */ -/* Important: This must be done before passing the struct to any mz_zip - * functions. */ +/* Important: This must be done before passing the struct to any mz_zip functions. */ MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive* pZip); MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive* pZip); @@ -1403,12 +1193,11 @@ MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive* pZip); MINIZ_EXPORT mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive* pZip); MINIZ_EXPORT MZ_FILE* mz_zip_get_cfile(mz_zip_archive* pZip); -/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. - */ +/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive* pZip, mz_uint64 file_ofs, void* pBuf, size_t n); -/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. - * These functions retrieve/manipulate this field. */ +/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this + * field. */ /* Note that the m_last_error functionality is not thread safe. */ MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive* pZip, mz_zip_error err_num); MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive* pZip); @@ -1422,14 +1211,13 @@ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive* pZip, mz_ /* MZ_TRUE if the file is encrypted/strong encrypted. */ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive* pZip, mz_uint file_index); -/* MZ_TRUE if the compression method is supported, and the file is not - * encrypted, and the file is not a compressed patch file. */ +/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch + * file. */ MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive* pZip, mz_uint file_index); /* Retrieves the filename of an archive file entry. */ -/* Returns the number of bytes written to pFilename, or if filename_buf_size is - * 0 this function returns the number of bytes needed to fully store the - * filename. */ +/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of + * bytes needed to fully store the filename. */ MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive* pZip, mz_uint file_index, char* pFilename, mz_uint filename_buf_size); @@ -1445,9 +1233,8 @@ MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive* pZip, const ch MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive* pZip, mz_uint file_index, mz_zip_archive_file_stat* pStat); /* MZ_TRUE if the file is in zip64 format. */ -/* A file is considered zip64 if it contained a zip64 end of central directory - * marker, or if it contained any zip64 extended file information fields in the - * central directory. */ +/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 + * extended file information fields in the central directory. */ MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive* pZip); /* Returns the total central directory size in bytes. */ @@ -1455,8 +1242,7 @@ MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive* pZip); MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive* pZip); /* Extracts a archive file to a memory buffer using no memory allocation. */ -/* There must be at least enough room on the stack to store the inflator's state - * (~34KB or so). */ +/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size); @@ -1471,16 +1257,14 @@ MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, con size_t buf_size, mz_uint flags); /* Extracts a archive file to a dynamically allocated heap buffer. */ -/* The memory will be allocated via the mz_zip_archive's alloc/realloc - * functions. */ +/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ /* Returns NULL and sets the last error on failure. */ MINIZ_EXPORT void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags); MINIZ_EXPORT void* mz_zip_reader_extract_file_to_heap(mz_zip_archive* pZip, const char* pFilename, size_t* pSize, mz_uint flags); -/* Extracts a archive file using a callback function to output the file's data. - */ +/* Extracts a archive file using a callback function to output the file's data. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_index, mz_file_write_func pCallback, void* pOpaque, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive* pZip, const char* pFilename, @@ -1497,16 +1281,14 @@ MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_s MINIZ_EXPORT mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); #ifndef MINIZ_NO_STDIO -/* Extracts a archive file to a disk file and sets its last accessed and - * modified times. */ +/* Extracts a archive file to a disk file and sets its last accessed and modified times. */ /* This function only extracts files, not archive directory records. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive* pZip, mz_uint file_index, const char* pDst_filename, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive* pZip, const char* pArchive_filename, const char* pDst_filename, mz_uint flags); -/* Extracts a archive file starting at the current position in the destination - * FILE stream. */ +/* Extracts a archive file starting at the current position in the destination FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive* pZip, mz_uint file_index, MZ_FILE* File, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive* pZip, const char* pArchive_filename, @@ -1517,32 +1299,27 @@ MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive* pZip, c /* TODO */ typedef void *mz_zip_streaming_extract_state_ptr; mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); - mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); - mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs); + uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); + mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); #endif -/* This function compares the archive's local headers, the optional local zip64 - * extended information block, and the optional descriptor following the - * compressed data vs. the data in the central directory. */ -/* It also validates that each file can be successfully uncompressed unless the - * MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ +/* This function compares the archive's local headers, the optional local zip64 extended information block, and the + * optional descriptor following the compressed data vs. the data in the central directory. */ +/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is + * specified. */ MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive* pZip, mz_uint file_index, mz_uint flags); -/* Validates an entire archive by calling mz_zip_validate_file() on each file. - */ +/* Validates an entire archive by calling mz_zip_validate_file() on each file. */ MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive* pZip, mz_uint flags); /* Misc utils/helpers, valid for ZIP reading or writing */ MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void* pMem, size_t size, mz_uint flags, mz_zip_error* pErr); -#ifndef MINIZ_NO_STDIO MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char* pFilename, mz_uint flags, mz_zip_error* pErr); -#endif -/* Universal end function - calls either mz_zip_reader_end() or - * mz_zip_writer_end(). */ +/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive* pZip); /* -------- ZIP writing */ @@ -1550,10 +1327,8 @@ MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive* pZip); #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS /* Inits a ZIP archive writer. */ -/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init - * or mz_zip_writer_init_v2*/ -/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases - * only by n*/ +/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ +/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive* pZip, mz_uint64 existing_size); MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive* pZip, mz_uint64 existing_size, mz_uint flags); @@ -1563,43 +1338,38 @@ MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive* pZip, size_t siz size_t initial_allocation_size, mz_uint flags); #ifndef MINIZ_NO_STDIO -MINIZ_EXPORT -mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning); +MINIZ_EXPORT mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, + mz_uint64 size_to_reserve_at_beginning); MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive* pZip, MZ_FILE* pFile, mz_uint flags); #endif -/* Converts a ZIP archive reader object into a writer object, to allow efficient - * in-place file appends to occur on an existing archive. */ -/* For archives opened using mz_zip_reader_init_file, pFilename must be the - * archive's filename so it can be reopened for writing. If the file can't be - * reopened, mz_zip_reader_end() will be called. */ -/* For archives opened using mz_zip_reader_init_mem, the memory block must be - * growable using the realloc callback (which defaults to realloc unless you've - * overridden it). */ -/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's - * user provided m_pWrite function cannot be NULL. */ -/* Note: In-place archive modification is not recommended unless you know what - * you're doing, because if execution stops or something goes wrong before */ +/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an + * existing archive. */ +/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for + * writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ +/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which + * defaults to realloc unless you've overridden it). */ +/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be + * NULL. */ +/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops + * or something goes wrong before */ /* the archive is finalized the file's central directory will be hosed. */ MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive* pZip, const char* pFilename); MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive* pZip, const char* pFilename, mz_uint flags); -/* Adds the contents of a memory buffer to an archive. These functions record - * the current local time into the archive. */ -/* To add a directory entry, call this method with an archive name ending in a - * forwardslash with an empty buffer. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, - * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or - * just set to MZ_DEFAULT_COMPRESSION. */ +/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. + */ +/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or + * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, mz_uint level_and_flags); -/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, - * and optionally supply the function with already compressed data. */ -/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA - * flag is specified. */ +/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with + * already compressed data. */ +/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ MINIZ_EXPORT 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); @@ -1611,10 +1381,9 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive* pZip, const cha mz_uint user_extra_data_local_len, const char* user_extra_data_central, mz_uint user_extra_data_central_len); -/* 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.*/ +/* 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.*/ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive* pZip, const char* pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 max_size, const MZ_TIME_T* pFile_time, const void* pComment, mz_uint16 comment_size, @@ -1622,16 +1391,14 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( const char* user_extra_data_central, mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO -/* Adds the contents of a disk file to an archive. This function also records - * the disk file's modified time into the archive. */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, - * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or - * just set to MZ_DEFAULT_COMPRESSION. */ +/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the + * archive. */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or + * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, const char* pSrc_filename, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags); -/* Like mz_zip_writer_add_file(), except the file data is read from the - * specified FILE stream. */ +/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(mz_zip_archive* pZip, const char* pArchive_name, MZ_FILE* pSrc_file, mz_uint64 max_size, const MZ_TIME_T* pFile_time, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags, @@ -1640,46 +1407,35 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(mz_zip_archive* pZip, const char* p #endif /* Adds a file to an archive by fully cloning the data from another archive. */ -/* This function fully clones the source file's compressed data (no - * recompression), along with its full filename, extra data (it may add or - * modify the zip64 local header extra data field), and the optional descriptor - * following the compressed data. */ +/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra + * data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the + * compressed data. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* pSource_zip, mz_uint src_file_index); -/* Finalizes the archive by writing the central directory records followed by - * the end of central directory record. */ -/* After an archive is finalized, the only valid call on the mz_zip_archive - * struct is mz_zip_writer_end(). */ -/* An archive must be manually finalized by calling this function for it to be - * valid. */ +/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ +/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ +/* An archive must be manually finalized by calling this function for it to be valid. */ MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip); -/* Finalizes a heap archive, returning a pointer to the heap block and its size. - */ -/* The heap block will be allocated using the mz_zip_archive's alloc/realloc - * callbacks. */ +/* Finalizes a heap archive, returning a poiner to the heap block and its size. */ +/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive* pZip, void** ppBuf, size_t* pSize); -/* Ends archive writing, freeing all allocations, and closing the output file if - * mz_zip_writer_init_file() was used. */ -/* Note for the archive to be valid, it *must* have been finalized before ending - * (this function will not do it for you). */ +/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ +/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). + */ MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive* pZip); /* -------- Misc. high-level helper functions: */ -/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) - * appends a memory blob to a ZIP archive. */ -/* Note this is NOT a fully safe operation. If it crashes or dies in some way - * your archive can be left in a screwed up state (without a central directory). - */ -/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, - * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or - * just set to MZ_DEFAULT_COMPRESSION. */ -/* TODO: Perhaps add an option to leave the existing central dir in place in - * case the add dies? We could then truncate the file (so the old central dir - * would be at the end) if something goes wrong. */ +/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ +/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up + * state (without a central directory). */ +/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or + * more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ +/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate + * the file (so the old central dir would be at the end) if something goes wrong. */ MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place(const char* pZip_filename, const char* pArchive_name, const void* pBuf, size_t buf_size, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags); @@ -1688,17 +1444,14 @@ MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char* pZip mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error* pErr); -#ifndef MINIZ_NO_STDIO /* Reads a single file from an archive into a heap block. */ -/* If pComment is not NULL, only the file with the specified comment will be - * extracted. */ +/* If pComment is not NULL, only the file with the specified comment will be extracted. */ /* Returns NULL on failure. */ MINIZ_EXPORT void* mz_zip_extract_archive_file_to_heap(const char* pZip_filename, const char* pArchive_name, size_t* pSize, mz_uint flags); MINIZ_EXPORT void* mz_zip_extract_archive_file_to_heap_v2(const char* pZip_filename, const char* pArchive_name, const char* pComment, size_t* pSize, mz_uint flags, mz_zip_error* pErr); -#endif #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ diff --git a/src/screens/EpubReaderScreen.cpp b/src/screens/EpubReaderScreen.cpp index 5a87fc1..ed6c53a 100644 --- a/src/screens/EpubReaderScreen.cpp +++ b/src/screens/EpubReaderScreen.cpp @@ -135,6 +135,7 @@ void EpubReaderScreen::displayTaskLoop() { } } +// TODO: Failure handling void EpubReaderScreen::renderPage() { if (!epub) { return;