mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 15:31:39 +00:00
3af9ad4e04
uses a customized and highly stripped down miniz version. also move localization file reads to SDL_RWops, and update the documentation.
699 lines
30 KiB
C
699 lines
30 KiB
C
#define MINIZ_EXPORT
|
|
/* 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 <richgel99@gmail.com>, 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).
|
|
|
|
* 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.
|
|
|
|
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.
|
|
|
|
* 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:
|
|
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.
|
|
|
|
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.
|
|
|
|
* 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.
|
|
|
|
- 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);
|
|
|
|
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:
|
|
|
|
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
|
|
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().
|
|
|
|
- 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.
|
|
|
|
- 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);
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
* 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
|
|
|
|
* 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
|
|
|
|
|
|
#if 1 /* QUAKESPASM-SPECIFIC CONFIG: */
|
|
|
|
#if defined(SDL_FRAMEWORK) || defined(NO_SDL_CONFIG)
|
|
#ifdef USE_SDL2
|
|
#include <SDL2/SDL.h>
|
|
#else
|
|
#include <SDL/SDL.h>
|
|
#endif
|
|
#else
|
|
#include "SDL.h"
|
|
#endif
|
|
|
|
/* 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. */
|
|
|
|
/* 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. */
|
|
#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
|
|
|
|
/* 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_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. */
|
|
/*#define MINIZ_NO_MALLOC */
|
|
|
|
#define MINIZ_LITTLE_ENDIAN (SDL_BYTEORDER == SDL_LIL_ENDIAN)
|
|
|
|
#endif /* QUAKESPASM-SPECIFIC */
|
|
|
|
#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 */
|
|
#define MINIZ_NO_TIME
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
|
|
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
|
|
/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */
|
|
#define MINIZ_X86_OR_X64_CPU 1
|
|
#else
|
|
#define MINIZ_X86_OR_X64_CPU 0
|
|
#endif
|
|
|
|
/* Set MINIZ_LITTLE_ENDIAN only if not set */
|
|
#if !defined(MINIZ_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
|
|
#endif
|
|
|
|
#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 1
|
|
#define MINIZ_UNALIGNED_USE_MEMCPY
|
|
#else
|
|
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
|
|
#endif
|
|
#endif
|
|
|
|
#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). */
|
|
#define MINIZ_HAS_64BIT_REGISTERS 1
|
|
#else
|
|
#define MINIZ_HAS_64BIT_REGISTERS 0
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* ------------------- 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! */
|
|
typedef unsigned long mz_ulong;
|
|
|
|
#define MZ_CRC32_INIT (0)
|
|
#if 0
|
|
/* 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);
|
|
#endif
|
|
|
|
/* Method */
|
|
#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. */
|
|
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);
|
|
|
|
#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
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* ------------------- Types and macros */
|
|
typedef unsigned char mz_uint8;
|
|
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;
|
|
|
|
#define MZ_FALSE (0)
|
|
#define MZ_TRUE (1)
|
|
|
|
/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
|
|
#ifdef _MSC_VER
|
|
#define MZ_MACRO_END while (0, 0)
|
|
#else
|
|
#define MZ_MACRO_END while (0)
|
|
#endif
|
|
|
|
#define MZ_FILE void *
|
|
|
|
#define MZ_ASSERT(x) assert(x)
|
|
|
|
#define MZ_MALLOC(x) malloc(x)
|
|
#define MZ_FREE(x) free(x)
|
|
#define MZ_REALLOC(p, x) realloc(p, x)
|
|
|
|
#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))
|
|
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
|
|
#else
|
|
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
|
|
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
|
#endif
|
|
|
|
#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U))
|
|
|
|
#ifdef _MSC_VER
|
|
#define MZ_FORCEINLINE __forceinline
|
|
#elif defined(__GNUC__)
|
|
#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__))
|
|
#else
|
|
#define MZ_FORCEINLINE inline
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#if 0
|
|
extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items, size_t size);
|
|
extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address);
|
|
extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size);
|
|
#endif
|
|
|
|
#define MZ_UINT16_MAX (0xFFFFU)
|
|
#define MZ_UINT32_MAX (0xFFFFFFFFU)
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
/* ------------------- 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. */
|
|
enum
|
|
{
|
|
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
|
|
TINFL_FLAG_HAS_MORE_INPUT = 2,
|
|
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
|
|
TINFL_FLAG_COMPUTE_ADLER32 = 8
|
|
};
|
|
|
|
struct tinfl_decompressor_tag;
|
|
typedef struct tinfl_decompressor_tag tinfl_decompressor;
|
|
|
|
/* Max size of LZ dictionary. */
|
|
#define TINFL_LZ_DICT_SIZE 32768
|
|
|
|
/* 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. */
|
|
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.) */
|
|
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. */
|
|
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. */
|
|
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. */
|
|
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 */
|
|
/* 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 */
|
|
/* so I may need to add some code to address this. */
|
|
TINFL_STATUS_HAS_MORE_OUTPUT = 2
|
|
} tinfl_status;
|
|
|
|
/* Initializes the decompressor to its initial state. */
|
|
#define tinfl_init(r) \
|
|
do \
|
|
{ \
|
|
(r)->m_state = 0; \
|
|
} \
|
|
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. */
|
|
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);
|
|
|
|
/* Internal/private bits follow. */
|
|
enum
|
|
{
|
|
TINFL_MAX_HUFF_TABLES = 3,
|
|
TINFL_MAX_HUFF_SYMBOLS_0 = 288,
|
|
TINFL_MAX_HUFF_SYMBOLS_1 = 32,
|
|
TINFL_MAX_HUFF_SYMBOLS_2 = 19,
|
|
TINFL_FAST_LOOKUP_BITS = 10,
|
|
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
|
|
#define TINFL_USE_64BIT_BITBUF 0
|
|
#endif
|
|
|
|
#if TINFL_USE_64BIT_BITBUF
|
|
typedef mz_uint64 tinfl_bit_buf_t;
|
|
#define TINFL_BITBUF_SIZE (64)
|
|
#else
|
|
typedef mz_uint32 tinfl_bit_buf_t;
|
|
#define TINFL_BITBUF_SIZE (32)
|
|
#endif
|
|
|
|
struct tinfl_decompressor_tag
|
|
{
|
|
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, 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;
|
|
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];
|
|
};
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
|
|
|
|
|
|
/* ------------------- ZIP archive reading/writing */
|
|
|
|
#ifndef MINIZ_NO_ARCHIVE_APIS
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
/* 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
|
|
};
|
|
|
|
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. */
|
|
mz_uint64 m_central_dir_ofs;
|
|
|
|
/* These fields are copied directly from the zip's central dir. */
|
|
mz_uint16 m_version_made_by;
|
|
mz_uint16 m_version_needed;
|
|
mz_uint16 m_bit_flag;
|
|
mz_uint16 m_method;
|
|
|
|
/* 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. */
|
|
mz_uint64 m_uncomp_size;
|
|
|
|
/* Zip internal and external file attributes. */
|
|
mz_uint16 m_internal_attr;
|
|
mz_uint32 m_external_attr;
|
|
|
|
/* Entry's local header file offset in bytes. */
|
|
mz_uint64 m_local_header_ofs;
|
|
|
|
/* Size of comment in bytes. */
|
|
mz_uint32 m_comment_size;
|
|
|
|
/* 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_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_bool m_is_supported;
|
|
|
|
/* Filename. If string ends in '/' it's a subdirectory entry. */
|
|
/* Guaranteed to be zero terminated, may be truncated to fit. */
|
|
char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
|
|
|
|
/* Comment field. */
|
|
/* Guaranteed to be zero terminated, may be truncated to fit. */
|
|
char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
|
|
|
|
} mz_zip_archive_file_stat;
|
|
|
|
typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
|
|
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
|
|
typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
|
|
|
|
struct mz_zip_internal_state_tag;
|
|
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
|
|
|
|
typedef enum {
|
|
MZ_ZIP_MODE_INVALID = 0,
|
|
MZ_ZIP_MODE_READING = 1,
|
|
MZ_ZIP_MODE_WRITING = 2,
|
|
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
|
|
} mz_zip_mode;
|
|
|
|
typedef enum {
|
|
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
|
|
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_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_flags;
|
|
|
|
typedef enum {
|
|
MZ_ZIP_TYPE_INVALID = 0,
|
|
MZ_ZIP_TYPE_USER,
|
|
MZ_ZIP_TYPE_MEMORY,
|
|
MZ_ZIP_TYPE_HEAP,
|
|
MZ_ZIP_TYPE_FILE,
|
|
MZ_ZIP_TYPE_CFILE,
|
|
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. */
|
|
typedef enum {
|
|
MZ_ZIP_NO_ERROR = 0,
|
|
MZ_ZIP_UNDEFINED_ERROR,
|
|
MZ_ZIP_TOO_MANY_FILES,
|
|
MZ_ZIP_FILE_TOO_LARGE,
|
|
MZ_ZIP_UNSUPPORTED_METHOD,
|
|
MZ_ZIP_UNSUPPORTED_ENCRYPTION,
|
|
MZ_ZIP_UNSUPPORTED_FEATURE,
|
|
MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
|
|
MZ_ZIP_NOT_AN_ARCHIVE,
|
|
MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
|
|
MZ_ZIP_UNSUPPORTED_MULTIDISK,
|
|
MZ_ZIP_DECOMPRESSION_FAILED,
|
|
MZ_ZIP_COMPRESSION_FAILED,
|
|
MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
|
|
MZ_ZIP_CRC_CHECK_FAILED,
|
|
MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
|
|
MZ_ZIP_ALLOC_FAILED,
|
|
MZ_ZIP_FILE_OPEN_FAILED,
|
|
MZ_ZIP_FILE_CREATE_FAILED,
|
|
MZ_ZIP_FILE_WRITE_FAILED,
|
|
MZ_ZIP_FILE_READ_FAILED,
|
|
MZ_ZIP_FILE_CLOSE_FAILED,
|
|
MZ_ZIP_FILE_SEEK_FAILED,
|
|
MZ_ZIP_FILE_STAT_FAILED,
|
|
MZ_ZIP_INVALID_PARAMETER,
|
|
MZ_ZIP_INVALID_FILENAME,
|
|
MZ_ZIP_BUF_TOO_SMALL,
|
|
MZ_ZIP_INTERNAL_ERROR,
|
|
MZ_ZIP_FILE_NOT_FOUND,
|
|
MZ_ZIP_ARCHIVE_TOO_LARGE,
|
|
MZ_ZIP_VALIDATION_FAILED,
|
|
MZ_ZIP_WRITE_CALLBACK_FAILED,
|
|
MZ_ZIP_TOTAL_ERRORS
|
|
} mz_zip_error;
|
|
|
|
typedef struct
|
|
{
|
|
mz_uint64 m_archive_size;
|
|
mz_uint64 m_central_directory_file_ofs;
|
|
|
|
/* We only support up to UINT32_MAX files in zip64 mode. */
|
|
mz_uint32 m_total_files;
|
|
mz_zip_mode m_zip_mode;
|
|
mz_zip_type m_zip_type;
|
|
mz_zip_error m_last_error;
|
|
|
|
mz_uint64 m_file_offset_alignment;
|
|
|
|
mz_alloc_func m_pAlloc;
|
|
mz_free_func m_pFree;
|
|
mz_realloc_func m_pRealloc;
|
|
void *m_pAlloc_opaque;
|
|
|
|
mz_file_read_func m_pRead;
|
|
mz_file_write_func m_pWrite;
|
|
mz_file_needs_keepalive m_pNeeds_keepalive;
|
|
void *m_pIO_opaque;
|
|
|
|
mz_zip_internal_state *m_pState;
|
|
|
|
} mz_zip_archive;
|
|
|
|
/* -------- ZIP reading */
|
|
|
|
/* Inits a ZIP archive reader. */
|
|
/* These functions read and validate the archive's central directory. */
|
|
MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags);
|
|
|
|
/* 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 */
|
|
|
|
MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip);
|
|
MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip);
|
|
|
|
/* Returns the total number of files in the archive. */
|
|
MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
|
|
|
|
MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(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. */
|
|
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. */
|
|
/* 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);
|
|
MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip);
|
|
MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip);
|
|
MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err);
|
|
|
|
/* MZ_TRUE if the archive file entry is a directory entry. */
|
|
MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
|
|
|
|
/* 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. */
|
|
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. */
|
|
MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
|
|
|
|
/* Attempts to locates a file in the archive's central directory. */
|
|
/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
|
|
/* Returns -1 if the file cannot be found. */
|
|
MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
|
|
MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index);
|
|
|
|
/* Returns detailed information about an archive file entry. */
|
|
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. */
|
|
MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip);
|
|
|
|
/* Returns the total central directory size in bytes. */
|
|
/* The current max supported size is <= MZ_UINT32_MAX. */
|
|
MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip);
|
|
|
|
/* Extracts a archive file to a dynamically allocated heap buffer. */
|
|
/* 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);
|
|
|
|
/* 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);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* MINIZ_NO_ARCHIVE_APIS */
|