mirror of
https://github.com/openharmony/third_party_meshoptimizer.git
synced 2026-07-20 23:46:19 -04:00
Replace miniz with sdefl
This change replaces the old custom version of miniz with sdefl. sdefl has less code, doesn't require modifications and performs about as well. New versions of sdefl are available on https://github.com/vurtun/lib
This commit is contained in:
+1
-1
@@ -79,7 +79,7 @@ endif()
|
||||
set(TARGETS meshoptimizer)
|
||||
|
||||
if(MESHOPT_BUILD_DEMO)
|
||||
add_executable(demo demo/main.cpp demo/miniz.cpp demo/tests.cpp tools/meshloader.cpp)
|
||||
add_executable(demo demo/main.cpp demo/tests.cpp tools/meshloader.cpp)
|
||||
target_link_libraries(demo meshoptimizer)
|
||||
endif()
|
||||
|
||||
|
||||
+11
-5
@@ -9,7 +9,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "../extern/fast_obj.h"
|
||||
#include "miniz.h"
|
||||
|
||||
#define SDEFL_IMPLEMENTATION
|
||||
#include "../extern/sdefl.h"
|
||||
|
||||
// This file uses assert() to verify algorithm correctness
|
||||
#undef NDEBUG
|
||||
@@ -564,11 +566,11 @@ void optimize(const Mesh& mesh, const char* name, void (*optf)(Mesh& mesh))
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t compress(const std::vector<T>& data)
|
||||
size_t compress(const std::vector<T>& data, int level = SDEFL_LVL_DEF)
|
||||
{
|
||||
std::vector<unsigned char> cbuf(tdefl_compress_bound(data.size() * sizeof(T)));
|
||||
unsigned int flags = tdefl_create_comp_flags_from_zip_params(MZ_DEFAULT_LEVEL, 15, MZ_DEFAULT_STRATEGY);
|
||||
return tdefl_compress_mem_to_mem(&cbuf[0], cbuf.size(), &data[0], data.size() * sizeof(T), flags);
|
||||
std::vector<unsigned char> cbuf(sdefl_bound(int(data.size() * sizeof(T))));
|
||||
sdefl s = {};
|
||||
return sdeflate(&s, &cbuf[0], reinterpret_cast<const unsigned char*>(&data[0]), int(data.size() * sizeof(T)), level);
|
||||
}
|
||||
|
||||
void encodeIndex(const Mesh& mesh, char desc)
|
||||
@@ -1082,6 +1084,10 @@ void processDev(const char* path)
|
||||
strip.resize(meshopt_stripify(&strip[0], ©strip.indices[0], copystrip.indices.size(), copystrip.vertices.size(), 0));
|
||||
|
||||
encodeIndexSequence(strip, copystrip.vertices.size(), 'D');
|
||||
|
||||
packVertex<PackedVertex>(copy, "");
|
||||
encodeVertex<PackedVertex>(copy, "");
|
||||
encodeVertex<PackedVertexOct>(copy, "O");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
|
||||
-1197
File diff suppressed because it is too large
Load Diff
-298
@@ -1,298 +0,0 @@
|
||||
/* This is miniz.c with removal of all zlib/zip like functionality - only tdefl/tinfl APIs are left
|
||||
For maximum compatibility unaligned load/store and 64-bit register paths have been removed so this is slower than miniz.c
|
||||
|
||||
miniz.c v1.15 - 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
|
||||
*/
|
||||
|
||||
#ifndef MINIZ_HEADER_INCLUDED
|
||||
#define MINIZ_HEADER_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// 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
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 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.
|
||||
void mz_free(void *p);
|
||||
|
||||
// Compression strategies.
|
||||
enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
|
||||
|
||||
// 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, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 };
|
||||
|
||||
// Window bits
|
||||
#define MZ_DEFAULT_WINDOW_BITS 15
|
||||
|
||||
// Method
|
||||
#define MZ_DEFLATED 8
|
||||
|
||||
// ------------------- 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 long long mz_int64;
|
||||
typedef unsigned long long mz_uint64;
|
||||
typedef int mz_bool;
|
||||
|
||||
#define MZ_FALSE (0)
|
||||
#define MZ_TRUE (1)
|
||||
|
||||
// An attempt to work 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_ADLER32_INIT (1)
|
||||
// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
|
||||
mz_uint32 mz_adler32(mz_uint32 adler, const unsigned char *ptr, size_t buf_len);
|
||||
|
||||
// ------------------- Low-level Decompression API Definitions
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// High level decompression functions:
|
||||
// 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))
|
||||
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.
|
||||
// Returns 1 on success or 0 on failure.
|
||||
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
|
||||
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
|
||||
|
||||
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
|
||||
{
|
||||
TINFL_STATUS_BAD_PARAM = -3,
|
||||
TINFL_STATUS_ADLER32_MISMATCH = -2,
|
||||
TINFL_STATUS_FAILED = -1,
|
||||
TINFL_STATUS_DONE = 0,
|
||||
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
|
||||
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.
|
||||
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;
|
||||
|
||||
typedef mz_uint32 tinfl_bit_buf_t;
|
||||
#define TINFL_BITBUF_SIZE (32)
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
// ------------------- 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).
|
||||
#define TDEFL_LESS_MEMORY 0
|
||||
|
||||
// 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_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).
|
||||
enum
|
||||
{
|
||||
TDEFL_WRITE_ZLIB_HEADER = 0x01000,
|
||||
TDEFL_COMPUTE_ADLER32 = 0x02000,
|
||||
TDEFL_GREEDY_PARSING_FLAG = 0x04000,
|
||||
TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
|
||||
TDEFL_RLE_MATCHES = 0x10000,
|
||||
TDEFL_FILTER_MATCHES = 0x20000,
|
||||
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
|
||||
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
|
||||
};
|
||||
|
||||
// High level compression functions:
|
||||
|
||||
|
||||
// tdefl_compress_bound() returns a (very) conservative upper bound on the amount of data that could be generated by calling tdefl_compress_*().
|
||||
size_t tdefl_compress_bound(size_t source_len);
|
||||
|
||||
// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
|
||||
// Returns 0 on failure.
|
||||
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);
|
||||
|
||||
// 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.
|
||||
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);
|
||||
|
||||
enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, 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).
|
||||
#if TDEFL_LESS_MEMORY
|
||||
enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
|
||||
#else
|
||||
enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, 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, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
|
||||
#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.
|
||||
typedef enum
|
||||
{
|
||||
TDEFL_STATUS_BAD_PARAM = -2,
|
||||
TDEFL_STATUS_PUT_BUF_FAILED = -1,
|
||||
TDEFL_STATUS_OKAY = 0,
|
||||
TDEFL_STATUS_DONE = 1,
|
||||
} tdefl_status;
|
||||
|
||||
// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
|
||||
typedef enum
|
||||
{
|
||||
TDEFL_NO_FLUSH = 0,
|
||||
TDEFL_SYNC_FLUSH = 2,
|
||||
TDEFL_FULL_FLUSH = 3,
|
||||
TDEFL_FINISH = 4
|
||||
} tdefl_flush;
|
||||
|
||||
// tdefl's compression state structure.
|
||||
typedef struct
|
||||
{
|
||||
tdefl_put_buf_func_ptr m_pPut_buf_func;
|
||||
void *m_pPut_buf_user;
|
||||
mz_uint m_flags, m_max_probes[2];
|
||||
int m_greedy_parsing;
|
||||
mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
|
||||
mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
|
||||
mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
|
||||
mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
|
||||
tdefl_status m_prev_return_status;
|
||||
const void *m_pIn_buf;
|
||||
void *m_pOut_buf;
|
||||
size_t *m_pIn_buf_size, *m_pOut_buf_size;
|
||||
tdefl_flush m_flush;
|
||||
const mz_uint8 *m_pSrc;
|
||||
size_t m_src_buf_left, m_out_buf_ofs;
|
||||
mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
|
||||
mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
|
||||
mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
|
||||
mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
|
||||
mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
|
||||
mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
|
||||
} 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.)
|
||||
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.
|
||||
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() always consumes the entire input buffer.
|
||||
tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
|
||||
|
||||
tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
|
||||
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)
|
||||
// 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
|
||||
mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MINIZ_HEADER_INCLUDED
|
||||
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
Vendored
+666
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
# Small Deflate
|
||||
`sdefl` is a small bare bone lossless compression library in ANSI C (ISO C90)
|
||||
which implements the Deflate (RFC 1951) compressed data format specification standard.
|
||||
It is mainly tuned to get as much speed and compression ratio from as little code
|
||||
as needed to keep the implementation as concise as possible.
|
||||
|
||||
## Features
|
||||
- Portable single header and source file duo written in ANSI C (ISO C90)
|
||||
- Dual license with either MIT or public domain
|
||||
- Small implementation
|
||||
- Deflate: 525 LoC
|
||||
- Inflate: 320 LoC
|
||||
- Webassembly:
|
||||
- Deflate ~3.7 KB (~2.2KB compressed)
|
||||
- Inflate ~3.6 KB (~2.2KB compressed)
|
||||
|
||||
## Usage:
|
||||
This file behaves differently depending on what symbols you define
|
||||
before including it.
|
||||
|
||||
Header-File mode:
|
||||
If you do not define `SDEFL_IMPLEMENTATION` before including this file, it
|
||||
will operate in header only mode. In this mode it declares all used structs
|
||||
and the API of the library without including the implementation of the library.
|
||||
|
||||
Implementation mode:
|
||||
If you define `SDEFL_IMPLEMENTATION` before including this file, it will
|
||||
compile the implementation of the JSON parser. Make sure that you only include
|
||||
this file implementation in *one* C or C++ file to prevent collisions.
|
||||
|
||||
### Benchmark
|
||||
|
||||
| Compressor name | Compression| Decompress.| Compr. size | Ratio |
|
||||
| ------------------------| -----------| -----------| ----------- | ----- |
|
||||
| sdefl 1.0 -0 | 127 MB/s | 226 MB/s | 40004116 | 39.88 |
|
||||
| sdefl 1.0 -1 | 111 MB/s | 251 MB/s | 38940674 | 38.82 |
|
||||
| sdefl 1.0 -5 | 45 MB/s | 264 MB/s | 36577183 | 36.46 |
|
||||
| sdefl 1.0 -7 | 38 MB/s | 264 MB/s | 36523781 | 36.41 |
|
||||
| zlib 1.2.11 -1 | 72 MB/s | 307 MB/s | 42298774 | 42.30 |
|
||||
| zlib 1.2.11 -6 | 24 MB/s | 313 MB/s | 36548921 | 36.55 |
|
||||
| zlib 1.2.11 -9 | 20 MB/s | 314 MB/s | 36475792 | 36.48 |
|
||||
| miniz 1.0 -1 | 122 MB/s | 208 MB/s | 48510028 | 48.51 |
|
||||
| miniz 1.0 -6 | 27 MB/s | 260 MB/s | 36513697 | 36.51 |
|
||||
| miniz 1.0 -9 | 23 MB/s | 261 MB/s | 36460101 | 36.46 |
|
||||
| libdeflate 1.3 -1 | 147 MB/s | 667 MB/s | 39597378 | 39.60 |
|
||||
| libdeflate 1.3 -6 | 69 MB/s | 689 MB/s | 36648318 | 36.65 |
|
||||
| libdeflate 1.3 -9 | 13 MB/s | 672 MB/s | 35197141 | 35.20 |
|
||||
| libdeflate 1.3 -12 | 8.13 MB/s | 670 MB/s | 35100568 | 35.10 |
|
||||
|
||||
### Compression
|
||||
Results on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia):
|
||||
|
||||
| File | Original | `sdefl 0` | `sdefl 5` | `sdefl 7` |
|
||||
| :------ | ---------: | -----------------: | ---------: | ----------: |
|
||||
| dickens | 10.192.446 | 4,260,187| 3,845,261| 3,833,657 |
|
||||
| mozilla | 51.220.480 | 20,774,706 | 19,607,009 | 19,565,867 |
|
||||
| mr | 9.970.564 | 3,860,531 | 3,673,460 | 3,665,627 |
|
||||
| nci | 33.553.445 | 4,030,283 | 3,094,526 | 3,006,075 |
|
||||
| ooffice | 6.152.192 | 3,320,063 | 3,186,373 | 3,183,815 |
|
||||
| osdb | 10.085.684 | 3,919,646 | 3,649,510 | 3,649,477 |
|
||||
| reymont | 6.627.202 | 2,263,378 | 1,857,588 | 1,827,237 |
|
||||
| samba | 21.606.400 | 6,121,797 | 5,462,670 | 5,450,762 |
|
||||
| sao | 7.251.944 | 5,612,421 | 5,485,380 | 5,481,765 |
|
||||
| webster | 41.458.703 | 13,972,648 | 12,059,432 | 11,991,421 |
|
||||
| xml | 5.345.280 | 886,620| 674,009 | 662,141 |
|
||||
| x-ray | 8.474.240 | 6,304,655 | 6,244,779 | 6,244,779 |
|
||||
|
||||
## License
|
||||
```
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2020 Micha Mettke
|
||||
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.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
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 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 SDEFL_H_INCLUDED
|
||||
#define SDEFL_H_INCLUDED
|
||||
|
||||
#define SDEFL_MAX_OFF (1 << 15)
|
||||
#define SDEFL_WIN_SIZ SDEFL_MAX_OFF
|
||||
#define SDEFL_WIN_MSK (SDEFL_WIN_SIZ-1)
|
||||
|
||||
#define SDEFL_HASH_BITS 15
|
||||
#define SDEFL_HASH_SIZ (1 << SDEFL_HASH_BITS)
|
||||
#define SDEFL_HASH_MSK (SDEFL_HASH_SIZ-1)
|
||||
|
||||
#define SDEFL_MIN_MATCH 4
|
||||
#define SDEFL_BLK_MAX (256*1024)
|
||||
#define SDEFL_SEQ_SIZ ((SDEFL_BLK_MAX + SDEFL_MIN_MATCH)/SDEFL_MIN_MATCH)
|
||||
|
||||
#define SDEFL_SYM_MAX (288)
|
||||
#define SDEFL_OFF_MAX (32)
|
||||
#define SDEFL_PRE_MAX (19)
|
||||
|
||||
#define SDEFL_LVL_MIN 0
|
||||
#define SDEFL_LVL_DEF 5
|
||||
#define SDEFL_LVL_MAX 8
|
||||
|
||||
struct sdefl_freq {
|
||||
unsigned lit[SDEFL_SYM_MAX];
|
||||
unsigned off[SDEFL_OFF_MAX];
|
||||
};
|
||||
struct sdefl_code_words {
|
||||
unsigned lit[SDEFL_SYM_MAX];
|
||||
unsigned off[SDEFL_OFF_MAX];
|
||||
};
|
||||
struct sdefl_lens {
|
||||
unsigned char lit[SDEFL_SYM_MAX];
|
||||
unsigned char off[SDEFL_OFF_MAX];
|
||||
};
|
||||
struct sdefl_codes {
|
||||
struct sdefl_code_words word;
|
||||
struct sdefl_lens len;
|
||||
};
|
||||
struct sdefl_seqt {
|
||||
int off, len;
|
||||
};
|
||||
struct sdefl {
|
||||
int bits, cnt;
|
||||
int tbl[SDEFL_HASH_SIZ];
|
||||
int prv[SDEFL_WIN_SIZ];
|
||||
|
||||
int seq_cnt;
|
||||
struct sdefl_seqt seq[SDEFL_SEQ_SIZ];
|
||||
struct sdefl_freq freq;
|
||||
struct sdefl_codes cod;
|
||||
};
|
||||
extern int sdefl_bound(int in_len);
|
||||
extern int sdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
|
||||
extern int zsdeflate(struct sdefl *s, void *o, const void *i, int n, int lvl);
|
||||
|
||||
#endif /* SDEFL_H_INCLUDED */
|
||||
|
||||
#ifdef SDEFL_IMPLEMENTATION
|
||||
|
||||
#include <assert.h> /* assert */
|
||||
#include <string.h> /* memcpy */
|
||||
#include <limits.h> /* CHAR_BIT */
|
||||
|
||||
#define SDEFL_NIL (-1)
|
||||
#define SDEFL_MAX_MATCH 258
|
||||
#define SDEFL_MAX_CODE_LEN (15)
|
||||
#define SDEFL_SYM_BITS (10u)
|
||||
#define SDEFL_SYM_MSK ((1u << SDEFL_SYM_BITS)-1u)
|
||||
#define SDEFL_LIT_LEN_CODES (14)
|
||||
#define SDEFL_OFF_CODES (15)
|
||||
#define SDEFL_PRE_CODES (7)
|
||||
#define SDEFL_CNT_NUM(n) ((((n)+3u/4u)+3u)&~3u)
|
||||
#define SDEFL_EOB (256)
|
||||
|
||||
#define sdefl_npow2(n) (1 << (sdefl_ilog2((n)-1) + 1))
|
||||
|
||||
static int
|
||||
sdefl_ilog2(int n) {
|
||||
if (!n) return 0;
|
||||
#ifdef _MSC_VER
|
||||
unsigned long msbp = 0;
|
||||
_BitScanReverse(&msbp, (unsigned long)n);
|
||||
return (int)msbp;
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
return (int)sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl((unsigned long)n);
|
||||
#else
|
||||
#define lt(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
|
||||
static const char tbl[256] = {
|
||||
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,lt(4), lt(5), lt(5), lt(6), lt(6), lt(6), lt(6),
|
||||
lt(7), lt(7), lt(7), lt(7), lt(7), lt(7), lt(7), lt(7)};
|
||||
int tt, t;
|
||||
if ((tt = (n >> 16))) {
|
||||
return (t = (tt >> 8)) ? 24 + tbl[t] : 16 + tbl[tt];
|
||||
} else {
|
||||
return (t = (n >> 8)) ? 8 + tbl[t] : tbl[n];
|
||||
}
|
||||
#undef lt
|
||||
#endif
|
||||
}
|
||||
static unsigned
|
||||
sdefl_uload32(const void *p) {
|
||||
/* hopefully will be optimized to an unaligned read */
|
||||
unsigned n = 0;
|
||||
memcpy(&n, p, sizeof(n));
|
||||
return n;
|
||||
}
|
||||
static unsigned
|
||||
sdefl_hash32(const void *p) {
|
||||
unsigned n = sdefl_uload32(p);
|
||||
return (n * 0x9E377989) >> (32 - SDEFL_HASH_BITS);
|
||||
}
|
||||
static void
|
||||
sdefl_put(unsigned char **dst, struct sdefl *s, int code, int bitcnt) {
|
||||
s->bits |= (code << s->cnt);
|
||||
s->cnt += bitcnt;
|
||||
while (s->cnt >= 8) {
|
||||
unsigned char *tar = *dst;
|
||||
*tar = (unsigned char)(s->bits & 0xFF);
|
||||
s->bits >>= 8;
|
||||
s->cnt -= 8;
|
||||
*dst = *dst + 1;
|
||||
}
|
||||
}
|
||||
static void
|
||||
sdefl_heap_sub(unsigned A[], unsigned len, unsigned sub) {
|
||||
unsigned c, p = sub;
|
||||
unsigned v = A[sub];
|
||||
while ((c = p << 1) <= len) {
|
||||
if (c < len && A[c + 1] > A[c]) c++;
|
||||
if (v >= A[c]) break;
|
||||
A[p] = A[c], p = c;
|
||||
}
|
||||
A[p] = v;
|
||||
}
|
||||
static void
|
||||
sdefl_heap_array(unsigned *A, unsigned len) {
|
||||
unsigned sub;
|
||||
for (sub = len >> 1; sub >= 1; sub--)
|
||||
sdefl_heap_sub(A, len, sub);
|
||||
}
|
||||
static void
|
||||
sdefl_heap_sort(unsigned *A, unsigned n) {
|
||||
A--;
|
||||
sdefl_heap_array(A, n);
|
||||
while (n >= 2) {
|
||||
unsigned tmp = A[n];
|
||||
A[n--] = A[1];
|
||||
A[1] = tmp;
|
||||
sdefl_heap_sub(A, n, 1);
|
||||
}
|
||||
}
|
||||
static unsigned
|
||||
sdefl_sort_sym(unsigned sym_cnt, unsigned *freqs,
|
||||
unsigned char *lens, unsigned *sym_out) {
|
||||
unsigned cnts[SDEFL_CNT_NUM(SDEFL_SYM_MAX)] = {0};
|
||||
unsigned cnt_num = SDEFL_CNT_NUM(sym_cnt);
|
||||
unsigned used_sym = 0;
|
||||
unsigned sym, i;
|
||||
for (sym = 0; sym < sym_cnt; sym++)
|
||||
cnts[freqs[sym] < cnt_num-1 ? freqs[sym]: cnt_num-1]++;
|
||||
for (i = 1; i < cnt_num; i++) {
|
||||
unsigned cnt = cnts[i];
|
||||
cnts[i] = used_sym;
|
||||
used_sym += cnt;
|
||||
}
|
||||
for (sym = 0; sym < sym_cnt; sym++) {
|
||||
unsigned freq = freqs[sym];
|
||||
if (freq) {
|
||||
unsigned idx = freq < cnt_num-1 ? freq : cnt_num-1;
|
||||
sym_out[cnts[idx]++] = sym | (freq << SDEFL_SYM_BITS);
|
||||
} else lens[sym] = 0;
|
||||
}
|
||||
sdefl_heap_sort(sym_out + cnts[cnt_num-2], cnts[cnt_num-1] - cnts[cnt_num-2]);
|
||||
return used_sym;
|
||||
}
|
||||
static void
|
||||
sdefl_build_tree(unsigned *A, unsigned sym_cnt) {
|
||||
unsigned i = 0, b = 0, e = 0;
|
||||
do {
|
||||
unsigned m, n, freq_shift;
|
||||
if (i != sym_cnt && (b == e || (A[i] >> SDEFL_SYM_BITS) <= (A[b] >> SDEFL_SYM_BITS)))
|
||||
m = i++;
|
||||
else m = b++;
|
||||
if (i != sym_cnt && (b == e || (A[i] >> SDEFL_SYM_BITS) <= (A[b] >> SDEFL_SYM_BITS)))
|
||||
n = i++;
|
||||
else n = b++;
|
||||
|
||||
freq_shift = (A[m] & ~SDEFL_SYM_MSK) + (A[n] & ~SDEFL_SYM_MSK);
|
||||
A[m] = (A[m] & SDEFL_SYM_MSK) | (e << SDEFL_SYM_BITS);
|
||||
A[n] = (A[n] & SDEFL_SYM_MSK) | (e << SDEFL_SYM_BITS);
|
||||
A[e] = (A[e] & SDEFL_SYM_MSK) | freq_shift;
|
||||
} while (sym_cnt - ++e > 1);
|
||||
}
|
||||
static void
|
||||
sdefl_gen_len_cnt(unsigned *A, unsigned root, unsigned *len_cnt,
|
||||
unsigned max_code_len) {
|
||||
int n;
|
||||
unsigned i;
|
||||
for (i = 0; i <= max_code_len; i++)
|
||||
len_cnt[i] = 0;
|
||||
len_cnt[1] = 2;
|
||||
|
||||
A[root] &= SDEFL_SYM_MSK;
|
||||
for (n = (int)root - 1; n >= 0; n--) {
|
||||
unsigned p = A[n] >> SDEFL_SYM_BITS;
|
||||
unsigned pdepth = A[p] >> SDEFL_SYM_BITS;
|
||||
unsigned depth = pdepth + 1;
|
||||
unsigned len = depth;
|
||||
|
||||
A[n] = (A[n] & SDEFL_SYM_MSK) | (depth << SDEFL_SYM_BITS);
|
||||
if (len >= max_code_len) {
|
||||
len = max_code_len;
|
||||
do len--; while (!len_cnt[len]);
|
||||
}
|
||||
len_cnt[len]--;
|
||||
len_cnt[len+1] += 2;
|
||||
}
|
||||
}
|
||||
static void
|
||||
sdefl_gen_codes(unsigned *A, unsigned char *lens, const unsigned *len_cnt,
|
||||
unsigned max_code_word_len, unsigned sym_cnt) {
|
||||
unsigned i, sym, len, nxt[SDEFL_MAX_CODE_LEN + 1];
|
||||
for (i = 0, len = max_code_word_len; len >= 1; len--) {
|
||||
unsigned cnt = len_cnt[len];
|
||||
while (cnt--) lens[A[i++] & SDEFL_SYM_MSK] = (unsigned char)len;
|
||||
}
|
||||
nxt[0] = nxt[1] = 0;
|
||||
for (len = 2; len <= max_code_word_len; len++)
|
||||
nxt[len] = (nxt[len-1] + len_cnt[len-1]) << 1;
|
||||
for (sym = 0; sym < sym_cnt; sym++)
|
||||
A[sym] = nxt[lens[sym]]++;
|
||||
}
|
||||
static unsigned
|
||||
sdefl_rev(unsigned c, unsigned char n) {
|
||||
c = ((c & 0x5555) << 1) | ((c & 0xAAAA) >> 1);
|
||||
c = ((c & 0x3333) << 2) | ((c & 0xCCCC) >> 2);
|
||||
c = ((c & 0x0F0F) << 4) | ((c & 0xF0F0) >> 4);
|
||||
c = ((c & 0x00FF) << 8) | ((c & 0xFF00) >> 8);
|
||||
return c >> (16-n);
|
||||
}
|
||||
static void
|
||||
sdefl_huff(unsigned char *lens, unsigned *codes, unsigned *freqs,
|
||||
unsigned num_syms, unsigned max_code_len) {
|
||||
unsigned c, *A = codes;
|
||||
unsigned len_cnt[SDEFL_MAX_CODE_LEN + 1];
|
||||
unsigned used_syms = sdefl_sort_sym(num_syms, freqs, lens, A);
|
||||
if (!used_syms) return;
|
||||
if (used_syms == 1) {
|
||||
unsigned s = A[0] & SDEFL_SYM_MSK;
|
||||
unsigned i = s ? s : 1;
|
||||
codes[0] = 0, lens[0] = 1;
|
||||
codes[i] = 1, lens[i] = 1;
|
||||
return;
|
||||
}
|
||||
sdefl_build_tree(A, used_syms);
|
||||
sdefl_gen_len_cnt(A, used_syms-2, len_cnt, max_code_len);
|
||||
sdefl_gen_codes(A, lens, len_cnt, max_code_len, num_syms);
|
||||
for (c = 0; c < num_syms; c++) {
|
||||
codes[c] = sdefl_rev(codes[c], lens[c]);
|
||||
}
|
||||
}
|
||||
static void
|
||||
sdefl_precode(unsigned *freqs, unsigned *items, unsigned *item_cnt,
|
||||
const unsigned char *lens, const unsigned cnt) {
|
||||
unsigned *at = items;
|
||||
unsigned run_start = 0;
|
||||
do {
|
||||
unsigned len = lens[run_start];
|
||||
unsigned run_end = run_start;
|
||||
do run_end++; while (run_end != cnt && len == lens[run_end]);
|
||||
if (!len) {
|
||||
while ((run_end - run_start) >= 11) {
|
||||
unsigned n = (run_end - run_start) - 11;
|
||||
unsigned xbits = n < 0x7f ? n : 0x7f;
|
||||
freqs[18]++;
|
||||
*at++ = 18u | (xbits << 5u);
|
||||
run_start += 11 + xbits;
|
||||
}
|
||||
if ((run_end - run_start) >= 3) {
|
||||
unsigned n = (run_end - run_start) - 3;
|
||||
unsigned xbits = n < 0x7 ? n : 0x7;
|
||||
freqs[17]++;
|
||||
*at++ = 17u | (xbits << 5u);
|
||||
run_start += 3 + xbits;
|
||||
}
|
||||
} else if ((run_end - run_start) >= 4) {
|
||||
freqs[len]++;
|
||||
*at++ = len;
|
||||
run_start++;
|
||||
do {
|
||||
unsigned xbits = (run_end - run_start) - 3;
|
||||
xbits = xbits < 0x03 ? xbits : 0x03;
|
||||
*at++ = 16 | (xbits << 5);
|
||||
run_start += 3 + xbits;
|
||||
freqs[16]++;
|
||||
} while ((run_end - run_start) >= 3);
|
||||
}
|
||||
while (run_start != run_end) {
|
||||
freqs[len]++;
|
||||
*at++ = len;
|
||||
run_start++;
|
||||
}
|
||||
} while (run_start != cnt);
|
||||
*item_cnt = (unsigned)(at - items);
|
||||
}
|
||||
static void
|
||||
sdefl_match_codes(int *ls, int *lc, int *dx, int *dc, int dist, int len) {
|
||||
static const short dxmax[] = {0,6,12,24,48,96,192,384,768,1536,3072,6144,12288,24576};
|
||||
static const unsigned char lslot[258+1] = {
|
||||
0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12,
|
||||
12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16,
|
||||
16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
|
||||
21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
|
||||
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
|
||||
26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
||||
27, 27, 28
|
||||
};
|
||||
*ls = lslot[len];
|
||||
*lc = 257 + *ls;
|
||||
*dx = sdefl_ilog2(sdefl_npow2(dist) >> 2);
|
||||
*dc = *dx ? ((*dx + 1) << 1) + (dist > dxmax[*dx]) : dist-1;
|
||||
}
|
||||
static void
|
||||
sdefl_match(unsigned char **dst, struct sdefl *s, int dist, int len) {
|
||||
static const char lxn[] = {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};
|
||||
static const short lmin[] = {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};
|
||||
static const short dmin[] = {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};
|
||||
|
||||
int ls, lc, dx, dc;
|
||||
sdefl_match_codes(&ls, &lc, &dx, &dc, dist, len);
|
||||
sdefl_put(dst, s, (int)s->cod.word.lit[lc], s->cod.len.lit[lc]);
|
||||
sdefl_put(dst, s, len - lmin[ls], lxn[ls]);
|
||||
sdefl_put(dst, s, (int)s->cod.word.off[dc], s->cod.len.off[dc]);
|
||||
sdefl_put(dst, s, dist - dmin[dc], dx);
|
||||
}
|
||||
static void
|
||||
sdefl_flush(unsigned char **dst, struct sdefl *s, int is_last,
|
||||
const unsigned char *in) {
|
||||
int j, n = 0;
|
||||
unsigned i, item_cnt = 0;
|
||||
unsigned codes[SDEFL_PRE_MAX];
|
||||
unsigned char lens[SDEFL_PRE_MAX];
|
||||
unsigned freqs[SDEFL_PRE_MAX] = {0};
|
||||
unsigned items[SDEFL_SYM_MAX + SDEFL_OFF_MAX];
|
||||
static const unsigned char perm[SDEFL_PRE_MAX] = {16,17,18,0,8,7,9,6,10,5,11,
|
||||
4,12,3,13,2,14,1,15};
|
||||
|
||||
/* huffman codes */
|
||||
s->freq.lit[SDEFL_EOB]++;
|
||||
sdefl_huff(s->cod.len.lit, s->cod.word.lit, s->freq.lit, SDEFL_SYM_MAX, SDEFL_LIT_LEN_CODES);
|
||||
sdefl_huff(s->cod.len.off, s->cod.word.off, s->freq.off, SDEFL_OFF_MAX, SDEFL_OFF_CODES);
|
||||
sdefl_precode(freqs, items, &item_cnt, s->cod.len.lit, SDEFL_SYM_MAX+SDEFL_OFF_MAX);
|
||||
sdefl_huff(lens, codes, freqs, SDEFL_PRE_MAX, SDEFL_PRE_CODES);
|
||||
|
||||
/* block header */
|
||||
sdefl_put(dst, s, is_last ? 0x01 : 0x00, 1); /* block */
|
||||
sdefl_put(dst, s, 0x02, 2); /* dynamic huffman */
|
||||
sdefl_put(dst, s, SDEFL_SYM_MAX - 257, 5);
|
||||
sdefl_put(dst, s, SDEFL_OFF_MAX - 1, 5);
|
||||
sdefl_put(dst, s, SDEFL_PRE_MAX - 4, 4);
|
||||
for (i = 0; i < SDEFL_PRE_MAX; ++i)
|
||||
sdefl_put(dst, s, lens[perm[i]], 3);
|
||||
for (i = 0; i < item_cnt; ++i) {
|
||||
unsigned sym = items[i] & 0x1F;
|
||||
sdefl_put(dst, s, (int)codes[sym], lens[sym]);
|
||||
if (sym < 16) continue;
|
||||
if (sym == 16) sdefl_put(dst, s, items[i] >> 5, 2);
|
||||
else if(sym == 17) sdefl_put(dst, s, items[i] >> 5, 3);
|
||||
else sdefl_put(dst, s, items[i] >> 5, 7);
|
||||
}
|
||||
/* block sequences */
|
||||
for (n = 0; n < s->seq_cnt; ++n) {
|
||||
if (s->seq[n].off >= 0)
|
||||
for (j = 0; j < s->seq[n].len; ++j) {
|
||||
int c = in[s->seq[n].off + j];
|
||||
sdefl_put(dst, s, (int)s->cod.word.lit[c], s->cod.len.lit[c]);
|
||||
}
|
||||
else sdefl_match(dst, s, -s->seq[n].off, s->seq[n].len);
|
||||
}
|
||||
sdefl_put(dst, s, (int)(s)->cod.word.lit[SDEFL_EOB], (s)->cod.len.lit[SDEFL_EOB]);
|
||||
memset(&s->freq, 0, sizeof(s->freq));
|
||||
s->seq_cnt = 0;
|
||||
}
|
||||
static void
|
||||
sdefl_seq(struct sdefl *s, int off, int len) {
|
||||
assert(s->seq_cnt + 2 < SDEFL_SEQ_SIZ);
|
||||
s->seq[s->seq_cnt].off = off;
|
||||
s->seq[s->seq_cnt].len = len;
|
||||
s->seq_cnt++;
|
||||
}
|
||||
static void
|
||||
sdefl_reg_match(struct sdefl *s, int off, int len) {
|
||||
int ls, lc, dx, dc;
|
||||
sdefl_match_codes(&ls, &lc, &dx, &dc, off, len);
|
||||
s->freq.lit[lc]++;
|
||||
s->freq.off[dc]++;
|
||||
}
|
||||
struct sdefl_match {
|
||||
int off;
|
||||
int len;
|
||||
};
|
||||
static void
|
||||
sdefl_fnd(struct sdefl_match *m, const struct sdefl *s,
|
||||
int chain_len, int max_match, const unsigned char *in, int p) {
|
||||
int i = s->tbl[sdefl_hash32(&in[p])];
|
||||
int limit = ((p-SDEFL_WIN_SIZ)<SDEFL_NIL)?SDEFL_NIL:(p-SDEFL_WIN_SIZ);
|
||||
while (i > limit) {
|
||||
if (in[i+m->len] == in[p+m->len] &&
|
||||
(sdefl_uload32(&in[i]) == sdefl_uload32(&in[p]))){
|
||||
int n = SDEFL_MIN_MATCH;
|
||||
while (n < max_match && in[i+n] == in[p+n]) n++;
|
||||
if (n > m->len) {
|
||||
m->len = n, m->off = p - i;
|
||||
if (n == max_match) break;
|
||||
}
|
||||
}
|
||||
if (!(--chain_len)) break;
|
||||
i = s->prv[i&SDEFL_WIN_MSK];
|
||||
}
|
||||
}
|
||||
static int
|
||||
sdefl_compr(struct sdefl *s, unsigned char *out, const unsigned char *in,
|
||||
int in_len, int lvl) {
|
||||
unsigned char *q = out;
|
||||
static const unsigned char pref[] = {8,10,14,24,30,48,65,96,130};
|
||||
int max_chain = (lvl < 8) ? (1<<(lvl+1)): (1<<13);
|
||||
int n, i = 0, litlen = 0;
|
||||
for (n = 0; n < SDEFL_HASH_SIZ; ++n) {
|
||||
s->tbl[n] = SDEFL_NIL;
|
||||
}
|
||||
do {int blk_end = i + SDEFL_BLK_MAX < in_len ? i + SDEFL_BLK_MAX : in_len;
|
||||
while (i < blk_end) {
|
||||
struct sdefl_match m = {0};
|
||||
int max_match = ((in_len-i)>SDEFL_MAX_MATCH) ? SDEFL_MAX_MATCH:(in_len-i);
|
||||
int nice_match = pref[lvl] < max_match ? pref[lvl] : max_match;
|
||||
int run = 1, inc = 1, run_inc;
|
||||
if (max_match > SDEFL_MIN_MATCH) {
|
||||
sdefl_fnd(&m, s, max_chain, max_match, in, i);
|
||||
}
|
||||
if (lvl >= 5 && m.len >= SDEFL_MIN_MATCH && m.len < nice_match){
|
||||
struct sdefl_match m2 = {0};
|
||||
sdefl_fnd(&m2, s, max_chain, m.len+1, in, i+1);
|
||||
m.len = (m2.len > m.len) ? 0 : m.len;
|
||||
}
|
||||
if (m.len >= SDEFL_MIN_MATCH) {
|
||||
if (litlen) {
|
||||
sdefl_seq(s, i - litlen, litlen);
|
||||
litlen = 0;
|
||||
}
|
||||
sdefl_seq(s, -m.off, m.len);
|
||||
sdefl_reg_match(s, m.off, m.len);
|
||||
if (lvl < 2 && m.len >= nice_match) {
|
||||
inc = m.len;
|
||||
} else {
|
||||
run = m.len;
|
||||
}
|
||||
} else {
|
||||
s->freq.lit[in[i]]++;
|
||||
litlen++;
|
||||
}
|
||||
run_inc = run * inc;
|
||||
if (in_len - (i + run_inc) > SDEFL_MIN_MATCH) {
|
||||
while (run-- > 0) {
|
||||
unsigned h = sdefl_hash32(&in[i]);
|
||||
s->prv[i&SDEFL_WIN_MSK] = s->tbl[h];
|
||||
s->tbl[h] = i, i += inc;
|
||||
}
|
||||
} else {
|
||||
i += run_inc;
|
||||
}
|
||||
}
|
||||
if (litlen) {
|
||||
sdefl_seq(s, i - litlen, litlen);
|
||||
litlen = 0;
|
||||
}
|
||||
sdefl_flush(&q, s, blk_end == in_len, in);
|
||||
} while (i < in_len);
|
||||
|
||||
if (s->cnt)
|
||||
sdefl_put(&q, s, 0x00, 8 - s->cnt);
|
||||
return (int)(q - out);
|
||||
}
|
||||
extern int
|
||||
sdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) {
|
||||
s->bits = s->cnt = 0;
|
||||
return sdefl_compr(s, (unsigned char*)out, (const unsigned char*)in, n, lvl);
|
||||
}
|
||||
static unsigned
|
||||
sdefl_adler32(unsigned adler32, const unsigned char *in, int in_len) {
|
||||
#define SDEFL_ADLER_INIT (1)
|
||||
const unsigned ADLER_MOD = 65521;
|
||||
unsigned s1 = adler32 & 0xffff;
|
||||
unsigned s2 = adler32 >> 16;
|
||||
unsigned blk_len, i;
|
||||
|
||||
blk_len = in_len % 5552;
|
||||
while (in_len) {
|
||||
for (i = 0; i + 7 < blk_len; i += 8) {
|
||||
s1 += in[0]; s2 += s1;
|
||||
s1 += in[1]; s2 += s1;
|
||||
s1 += in[2]; s2 += s1;
|
||||
s1 += in[3]; s2 += s1;
|
||||
s1 += in[4]; s2 += s1;
|
||||
s1 += in[5]; s2 += s1;
|
||||
s1 += in[6]; s2 += s1;
|
||||
s1 += in[7]; s2 += s1;
|
||||
in += 8;
|
||||
}
|
||||
for (; i < blk_len; ++i) {
|
||||
s1 += *in++, s2 += s1;
|
||||
}
|
||||
s1 %= ADLER_MOD;
|
||||
s2 %= ADLER_MOD;
|
||||
in_len -= blk_len;
|
||||
blk_len = 5552;
|
||||
}
|
||||
return (unsigned)(s2 << 16) + (unsigned)s1;
|
||||
}
|
||||
extern int
|
||||
zsdeflate(struct sdefl *s, void *out, const void *in, int n, int lvl) {
|
||||
int p = 0;
|
||||
unsigned a = 0;
|
||||
unsigned char *q = (unsigned char*)out;
|
||||
|
||||
s->bits = s->cnt = 0;
|
||||
sdefl_put(&q, s, 0x78, 8); /* deflate, 32k window */
|
||||
sdefl_put(&q, s, 0x01, 8); /* fast compression */
|
||||
q += sdefl_compr(s, q, (const unsigned char*)in, n, lvl);
|
||||
|
||||
/* append adler checksum */
|
||||
a = sdefl_adler32(SDEFL_ADLER_INIT, (const unsigned char*)in, n);
|
||||
for (p = 0; p < 4; ++p) {
|
||||
sdefl_put(&q, s, (a >> 24) & 0xFF, 8);
|
||||
a <<= 8;
|
||||
}
|
||||
return (int)(q - (unsigned char*)out);
|
||||
}
|
||||
extern int
|
||||
sdefl_bound(int len) {
|
||||
int a = 128 + (len * 110) / 100;
|
||||
int b = 128 + len + ((len / (31 * 1024)) + 1) * 5;
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
#endif /* SDEFL_IMPLEMENTATION */
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "../src/meshoptimizer.h"
|
||||
#include "../extern/fast_obj.h"
|
||||
#include "../demo/miniz.h"
|
||||
|
||||
#define SDEFL_IMPLEMENTATION
|
||||
#include "../extern/sdefl.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
@@ -194,11 +196,11 @@ Mesh objmesh(const char* path)
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t compress(const std::vector<T>& data, int level = MZ_DEFAULT_LEVEL)
|
||||
size_t compress(const std::vector<T>& data, int level = SDEFL_LVL_DEF)
|
||||
{
|
||||
std::vector<unsigned char> cbuf(tdefl_compress_bound(data.size() * sizeof(T)));
|
||||
unsigned int flags = tdefl_create_comp_flags_from_zip_params(level, 15, MZ_DEFAULT_STRATEGY);
|
||||
return tdefl_compress_mem_to_mem(&cbuf[0], cbuf.size(), &data[0], data.size() * sizeof(T), flags);
|
||||
std::vector<unsigned char> cbuf(sdefl_bound(int(data.size() * sizeof(T))));
|
||||
sdefl s = {};
|
||||
return sdeflate(&s, &cbuf[0], reinterpret_cast<const unsigned char*>(&data[0]), int(data.size() * sizeof(T)), level);
|
||||
}
|
||||
|
||||
void compute_metric(const State* state, const Mesh& mesh, float result[Profile_Count])
|
||||
|
||||
Reference in New Issue
Block a user