From de71d577e05e1c15ff31e140547ed6a15550f34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Podg=C3=B3rski?= Date: Wed, 16 Jun 2021 13:22:26 +0200 Subject: [PATCH] API to set custom global CRC-32 function (#191) * API to set custom global CRC-32 function --- README.md | 15 +++- src/miniz.h | 205 +++++++++------------------------------------------- src/zip.c | 12 ++- src/zip.h | 32 +++++--- 4 files changed, 79 insertions(+), 185 deletions(-) diff --git a/README.md b/README.md index f3ab3f0..51b4437 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ void zip_walk(struct zip_t *zip, const char *path) { } ``` -* Deletes zip archive entries. +* Delete zip archive entries. ```c char *entries[] = {"unused.txt", "remove.ini", "delete.me"}; @@ -256,6 +256,19 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'd'); zip_close(zip); ``` +* Use custom CRC-32 function. +```c +unsigned long my_crc32(unsigned long crc, const void *buf, size_t bufsize) { + uint32_t c = crc32_16bytes_prefetch(buf, bufsize, (uint32_t)crc); + return (unsigned long)c; +} + +//... +zip_crc32_func(my_crc32); + +zip_extract("foo.zip", "/tmp", NULL, NULL); +``` + # Bindings Compile zip library as a dynamic library. ```shell diff --git a/src/miniz.h b/src/miniz.h index f9821c9..57995d3 100644 --- a/src/miniz.h +++ b/src/miniz.h @@ -345,7 +345,7 @@ 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_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); +mz_ulong mz_crc32(mz_ulong crc, const void *ptr, size_t buf_len); // Compression strategies. enum { @@ -781,7 +781,6 @@ typedef struct { void *m_pIO_opaque; mz_zip_internal_state *m_pState; - } mz_zip_archive; typedef enum { @@ -1166,26 +1165,6 @@ 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). -// 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. -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); -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. typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, @@ -1417,11 +1396,12 @@ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C // implementation that balances processor cache usage against speed": // http://www.geocities.com/malbrain/ -mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { +mz_ulong mz_crc32(mz_ulong crc, const void *buf, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; + const mz_uint8 *ptr = (const mz_uint8 *)buf; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; @@ -1434,6 +1414,10 @@ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { return ~crcu32; } +typedef mz_ulong (*mz_crc32_func)(mz_ulong, const void *, size_t); + +static volatile mz_crc32_func def_crc32_func = mz_crc32; + void mz_free(void *p) { MZ_FREE(p); } #ifndef MINIZ_NO_ZLIB_APIS @@ -2816,8 +2800,9 @@ static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, { \ if (rle_repeat_count) { \ if (rle_repeat_count < 3) { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ - d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + d->m_huff_count[2][prev_code_size] = \ + (mz_uint16)(d->m_huff_count[2][prev_code_size] + \ + rle_repeat_count); \ while (rle_repeat_count--) \ packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } else { \ @@ -3400,12 +3385,13 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d) { if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && - ((mz_uint32)( - *(d->m_dict + (probe_pos & TDEFL_LZ_DICT_SIZE_MASK)) | - (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 1)) - << 8) | - (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 2)) - << 16)) == first_trigram)) { + ((mz_uint32)(*(d->m_dict + (probe_pos & TDEFL_LZ_DICT_SIZE_MASK)) | + (*(d->m_dict + + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 1)) + << 8) | + (*(d->m_dict + + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 2)) + << 16)) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + @@ -3976,129 +3962,6 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, // C and C99, so no big deal) #endif -// Simple PNG writer function by Alex Evans, 2011. Released into the public -// domain: https://gist.github.com/908299, more context at -// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. -// This is actually a modification of Alex's original code so PNG files -// generated by this function pass pngcheck. -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) { - // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was - // defined. - static const mz_uint s_tdefl_png_num_probes[11] = { - 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; - tdefl_compressor *pComp = - (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); - tdefl_output_buffer out_buf; - int i, bpl = w * num_chans, y, z; - mz_uint32 c; - *pLen_out = 0; - if (!pComp) - return NULL; - MZ_CLEAR_OBJ(out_buf); - out_buf.m_expandable = MZ_TRUE; - out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); - if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { - MZ_FREE(pComp); - return NULL; - } - // write dummy header - for (z = 41; z; --z) - tdefl_output_buffer_putter(&z, 1, &out_buf); - // compress image data - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, - s_tdefl_png_num_probes[MZ_MIN(10, level)] | - TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { - tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); - tdefl_compress_buffer(pComp, - (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, - bpl, TDEFL_NO_FLUSH); - } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != - TDEFL_STATUS_DONE) { - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - // write real header - *pLen_out = out_buf.m_size - 41; - { - static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; - mz_uint8 pnghdr[41] = {0x89, - 0x50, - 0x4e, - 0x47, - 0x0d, - 0x0a, - 0x1a, - 0x0a, - 0x00, - 0x00, - 0x00, - 0x0d, - 0x49, - 0x48, - 0x44, - 0x52, - 0, - 0, - (mz_uint8)(w >> 8), - (mz_uint8)w, - 0, - 0, - (mz_uint8)(h >> 8), - (mz_uint8)h, - 8, - chans[num_chans], - 0, - 0, - 0, - 0, - 0, - 0, - 0, - (mz_uint8)(*pLen_out >> 24), - (mz_uint8)(*pLen_out >> 16), - (mz_uint8)(*pLen_out >> 8), - (mz_uint8)*pLen_out, - 0x49, - 0x44, - 0x41, - 0x54}; - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); - for (i = 0; i < 4; ++i, c <<= 8) - ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); - memcpy(out_buf.m_pBuf, pnghdr, 41); - } - // write footer (IDAT CRC-32, followed by IEND chunk) - if (!tdefl_output_buffer_putter( - "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { - *pLen_out = 0; - MZ_FREE(pComp); - MZ_FREE(out_buf.m_pBuf); - return NULL; - } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, - *pLen_out + 4); - for (i = 0; i < 4; ++i, c <<= 8) - (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); - // compute final size of file, grab compressed data buffer and return - *pLen_out += 57; - MZ_FREE(pComp); - return out_buf.m_pBuf; -} -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, - int num_chans, size_t *pLen_out) { - // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we - // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's - // where #defined out) - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, - pLen_out, 6, MZ_FALSE); -} - #ifdef _MSC_VER #pragma warning(pop) #endif @@ -4119,7 +3982,7 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, static wchar_t *str2wstr(const char *str) { int len = strlen(str) + 1; - wchar_t *wstr = (wchar_t*)malloc(len * sizeof(wchar_t)); + wchar_t *wstr = (wchar_t *)malloc(len * sizeof(wchar_t)); MultiByteToWideChar(CP_UTF8, 0, str, len * sizeof(char), wstr, len); return wstr; } @@ -5359,8 +5222,9 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, (size_t)needed_size) != needed_size) return MZ_FALSE; return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || - (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, - (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + (def_crc32_func(MZ_CRC32_INIT, pBuf, + (size_t)file_stat.m_uncomp_size) == + file_stat.m_crc32); } // Decompress the file either directly from memory or from a file input @@ -5421,8 +5285,8 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, if (status == TINFL_STATUS_DONE) { // Make sure the entire file was decompressed, and check its CRC. if ((out_buf_ofs != file_stat.m_uncomp_size) || - (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, - (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + (def_crc32_func(MZ_CRC32_INIT, pBuf, (size_t)file_stat.m_uncomp_size) != + file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } @@ -5582,9 +5446,8 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) status = TINFL_STATUS_FAILED; else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = - (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, - (size_t)file_stat.m_comp_size); + file_crc32 = (mz_uint32)def_crc32_func(file_crc32, pRead_buf, + (size_t)file_stat.m_comp_size); // cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; // comp_remaining = 0; @@ -5598,7 +5461,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, } if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32( + file_crc32 = (mz_uint32)def_crc32_func( file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, @@ -5651,8 +5514,8 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, status = TINFL_STATUS_FAILED; break; } - file_crc32 = - (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + file_crc32 = (mz_uint32)def_crc32_func( + file_crc32, (const void *)pWrite_buf_cur, out_buf_size); if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { status = TINFL_STATUS_FAILED; break; @@ -6220,8 +6083,8 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, cur_archive_file_ofs += archive_name_size; if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { - uncomp_crc32 = - (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_crc32 = (mz_uint32)def_crc32_func(MZ_CRC32_INIT, + (const mz_uint8 *)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; @@ -6402,8 +6265,8 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, MZ_FCLOSE(pSrc_file); return MZ_FALSE; } - uncomp_crc32 = - (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_crc32 = (mz_uint32)def_crc32_func( + uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } @@ -6441,8 +6304,8 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) break; - uncomp_crc32 = (mz_uint32)mz_crc32( - uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_crc32 = + (mz_uint32)def_crc32_func(uncomp_crc32, pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, diff --git a/src/zip.c b/src/zip.c index 3e64899..d36e435 100644 --- a/src/zip.c +++ b/src/zip.c @@ -1219,8 +1219,8 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { pzip = &(zip->archive); if (buf && bufsize > 0) { zip->entry.uncomp_size += bufsize; - zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( - zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); + zip->entry.uncomp_crc32 = + (mz_uint32)def_crc32_func(zip->entry.uncomp_crc32, buf, bufsize); level = zip->level & 0xF; if (!level) { @@ -1620,3 +1620,11 @@ int zip_extract(const char *zipname, const char *dir, return zip_archive_extract(&zip_archive, dir, on_extract, arg); } + +void zip_crc32_func(unsigned long (*crc32_func)(unsigned long crc, + const void *buf, + size_t bufsize)) { + if (crc32_func) { + def_crc32_func = crc32_func; + } +} diff --git a/src/zip.h b/src/zip.h index 54b412d..69e5f3d 100644 --- a/src/zip.h +++ b/src/zip.h @@ -16,17 +16,17 @@ #include #ifndef ZIP_SHARED -# define ZIP_EXPORT +#define ZIP_EXPORT #else -# ifdef _WIN32 -# ifdef ZIP_BUILD_SHARED -# define ZIP_EXPORT __declspec(dllexport) -# else -# define ZIP_EXPORT __declspec(dllimport) -# endif -# else -# define ZIP_EXPORT __attribute__ ((visibility ("default"))) -# endif +#ifdef _WIN32 +#ifdef ZIP_BUILD_SHARED +#define ZIP_EXPORT __declspec(dllexport) +#else +#define ZIP_EXPORT __declspec(dllimport) +#endif +#else +#define ZIP_EXPORT __attribute__((visibility("default"))) +#endif #endif #ifdef __cplusplus @@ -286,7 +286,8 @@ extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf, * For large entries, please take a look at zip_entry_extract function. * * @return the return code - the number of bytes actually read on success. - * Otherwise a negative number (< 0) on error (e.g. bufsize is not large enough). + * Otherwise a negative number (< 0) on error (e.g. bufsize is not large + * enough). */ extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize); @@ -425,6 +426,15 @@ extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir, void *arg), void *arg); +/** + * Sets global CRC-32 checksum function. + * + * @param crc32_func crc32 function (init value, buffer, buffer size) + */ +extern ZIP_EXPORT void +zip_crc32_func(unsigned long (*crc32_func)(unsigned long crc, const void *buf, + size_t bufsize)); + /** @} */ #ifdef __cplusplus }