Created
October 31, 2013 05:14
-
-
Save nemequ/7244649 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From ae236ca3fc9cab42c1667639fcf5b41ed0669758 Mon Sep 17 00:00:00 2001 | |
From: Evan Nemerson <evan@coeus-group.com> | |
Date: Wed, 30 Oct 2013 22:12:46 -0700 | |
Subject: [PATCH] Add zlite plugin. | |
https://github.com/quixdb/squash/issues/21 | |
--- | |
plugins/CMakeLists.txt | 1 + | |
plugins/zlite/CMakeLists.txt | 5 + | |
plugins/zlite/squash-zlite.c | 376 ++++++++++++++++++++++ | |
plugins/zlite/zlite.c | 743 +++++++++++++++++++++++++++++++++++++++++++ | |
plugins/zlite/zlite.codecs | 1 + | |
plugins/zlite/zlite.h | 110 +++++++ | |
plugins/zlite/zlite.md | 14 + | |
7 files changed, 1250 insertions(+) | |
create mode 100644 plugins/zlite/CMakeLists.txt | |
create mode 100644 plugins/zlite/squash-zlite.c | |
create mode 100644 plugins/zlite/zlite.c | |
create mode 100644 plugins/zlite/zlite.codecs | |
create mode 100644 plugins/zlite/zlite.h | |
create mode 100644 plugins/zlite/zlite.md | |
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt | |
index 108f723..1f7b7d5 100644 | |
--- a/plugins/CMakeLists.txt | |
+++ b/plugins/CMakeLists.txt | |
@@ -16,6 +16,7 @@ set (plugins_available | |
snappy | |
wflz | |
zlib | |
+ zlite | |
zpaq) | |
foreach (plugin ${plugins_available}) | |
diff --git a/plugins/zlite/CMakeLists.txt b/plugins/zlite/CMakeLists.txt | |
new file mode 100644 | |
index 0000000..5b1bbc3 | |
--- /dev/null | |
+++ b/plugins/zlite/CMakeLists.txt | |
@@ -0,0 +1,5 @@ | |
+set (zlite_sources | |
+ squash-zlite.c | |
+ zlite.c) | |
+ | |
+squash_plugin_add (zlite zlite_sources) | |
diff --git a/plugins/zlite/squash-zlite.c b/plugins/zlite/squash-zlite.c | |
new file mode 100644 | |
index 0000000..b5fc1ee | |
--- /dev/null | |
+++ b/plugins/zlite/squash-zlite.c | |
@@ -0,0 +1,376 @@ | |
+/* Copyright (c) 2013 The Squash Authors | |
+ * | |
+ * 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. | |
+ * | |
+ * Authors: | |
+ * Evan Nemerson <evan@coeus-group.com> | |
+ */ | |
+ | |
+#include <assert.h> | |
+#include <stdlib.h> | |
+#include <string.h> | |
+#include <strings.h> | |
+#include <errno.h> | |
+ | |
+#include <squash/squash.h> | |
+ | |
+#include "zlite.h" | |
+ | |
+typedef struct SquashZliteStream_s { | |
+ SquashStream base_object; | |
+ | |
+ unsigned char* inbuf; | |
+ int inlen; | |
+ int inpos; | |
+ | |
+ unsigned char* outbuf; | |
+ int outlen; | |
+ int outpos; | |
+ | |
+ unsigned char hdr[ZLITE_BLOCK_HEADER_LEN]; | |
+ uint_fast8_t hdrpos; | |
+ int rlen; | |
+ | |
+ unsigned char workmem[ZLITE_WORK_MEM_LEN]; | |
+} SquashZliteStream; | |
+ | |
+SquashStatus squash_plugin_init_codec (SquashCodec* codec, SquashCodecFuncs* funcs); | |
+ | |
+static void squash_zlite_stream_init (SquashZliteStream* stream, | |
+ SquashCodec* codec, | |
+ SquashStreamType stream_type, | |
+ SquashOptions* options, | |
+ SquashDestroyNotify destroy_notify); | |
+static SquashZliteStream* squash_zlite_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options); | |
+static void squash_zlite_stream_destroy (void* stream); | |
+static void squash_zlite_stream_free (void* stream); | |
+ | |
+static size_t | |
+squash_zlite_get_max_compressed_size (SquashCodec* codec, size_t uncompressed_length) { | |
+ return ZLITE_BLOCK_MAX_COMPRESSED_LEN(uncompressed_length); | |
+} | |
+ | |
+static void | |
+squash_zlite_stream_init (SquashZliteStream* stream, | |
+ SquashCodec* codec, | |
+ SquashStreamType stream_type, | |
+ SquashOptions* options, | |
+ SquashDestroyNotify destroy_notify) { | |
+ squash_stream_init ((SquashStream*) stream, codec, stream_type, options, destroy_notify); | |
+ | |
+ stream->hdrpos = 0; | |
+ | |
+ stream->inbuf = NULL; | |
+ stream->inlen = 0; | |
+ stream->inpos = 0; | |
+ | |
+ stream->outbuf = NULL; | |
+ stream->outlen = 0; | |
+ stream->outpos = 0; | |
+} | |
+ | |
+static void | |
+squash_zlite_stream_destroy (void* stream) { | |
+ SquashZliteStream* zstr = (SquashZliteStream*) stream; | |
+ | |
+ if (zstr->inbuf != NULL) { | |
+ free (zstr->inbuf); | |
+ } | |
+ | |
+ if (zstr->outbuf != NULL) { | |
+ free (zstr->outbuf); | |
+ } | |
+ | |
+ squash_stream_destroy (stream); | |
+} | |
+ | |
+static void | |
+squash_zlite_stream_free (void* stream) { | |
+ squash_zlite_stream_destroy (stream); | |
+ free (stream); | |
+} | |
+ | |
+static SquashZliteStream* | |
+squash_zlite_stream_new (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) { | |
+ SquashZliteStream* stream = (SquashZliteStream*) malloc (sizeof (SquashZliteStream)); | |
+ squash_zlite_stream_init (stream, codec, stream_type, options, squash_zlite_stream_free); | |
+ return stream; | |
+} | |
+ | |
+static SquashStream* | |
+squash_zlite_create_stream (SquashCodec* codec, SquashStreamType stream_type, SquashOptions* options) { | |
+ return (SquashStream*) squash_zlite_stream_new (codec, stream_type, options); | |
+} | |
+ | |
+#ifndef MIN | |
+#define MIN(a,b) (((a) < (b)) ? (a) : (b)) | |
+#endif | |
+ | |
+static SquashStatus | |
+squash_zlite_compress_stream (SquashStream* stream, bool flush) { | |
+ SquashZliteStream* zstr = (SquashZliteStream*) stream; | |
+ size_t copy_size = 0; | |
+ bool progress = false; | |
+ | |
+ /* Try to clear the output buffer */ | |
+ if (zstr->outlen > 0) { | |
+ copy_size = MIN(stream->avail_out, zstr->outlen - zstr->outpos); | |
+ | |
+ memcpy (stream->next_out, zstr->outbuf + zstr->outpos, copy_size); | |
+ stream->avail_out -= copy_size; | |
+ stream->next_out += copy_size; | |
+ zstr->outpos += copy_size; | |
+ if (zstr->outpos == zstr->outlen) { | |
+ zstr->outlen = 0; | |
+ zstr->outpos = 0; | |
+ } | |
+ | |
+ if (copy_size > 0) { | |
+ return (zstr->outlen != 0 || stream->avail_in > 0) ? SQUASH_PROCESSING : SQUASH_OK; | |
+ } else { | |
+ return SQUASH_PROCESSING; | |
+ } | |
+ } | |
+ | |
+ /* Fill the input buffer. */ | |
+ if ((stream->avail_in > 0) && ((zstr->inlen > 0) || ((stream->avail_in < ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN) && !flush))) { | |
+ copy_size = MIN(stream->avail_in, ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN - zstr->inlen); | |
+ if (zstr->inbuf == NULL) { | |
+ zstr->inbuf = (unsigned char*) malloc (ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN); | |
+ } | |
+ memcpy (zstr->inbuf + zstr->inlen, stream->next_in, copy_size); | |
+ stream->next_in += copy_size; | |
+ stream->avail_in -= copy_size; | |
+ zstr->inlen += copy_size; | |
+ progress = true; | |
+ } | |
+ | |
+ /* Perform the compression */ | |
+ if (flush || (zstr->inlen == ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN) || (stream->avail_in == ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)) { | |
+ unsigned char* outbuf; | |
+ int outlen; | |
+ unsigned char* inbuf; | |
+ int inlen; | |
+ | |
+ if (stream->avail_out >= ZLITE_BLOCK_MAX_COMPRESSED_LEN(ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)) { | |
+ outbuf = stream->next_out; | |
+ } else { | |
+ if (zstr->outbuf == NULL) { | |
+ zstr->outbuf = (unsigned char*) malloc (ZLITE_BLOCK_MAX_COMPRESSED_LEN(ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)); | |
+ if (zstr->outbuf == NULL) { | |
+ return SQUASH_MEMORY; | |
+ } | |
+ } | |
+ outbuf = zstr->outbuf; | |
+ } | |
+ | |
+ if (zstr->inlen > 0) { | |
+ inbuf = zstr->inbuf; | |
+ inlen = zstr->inlen; | |
+ } else { | |
+ inbuf = (unsigned char*) stream->next_in; | |
+ inlen = MIN(stream->avail_in, ZLITE_BLOCK_MAX_COMPRESSED_LEN(ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)); | |
+ } | |
+ | |
+ outlen = zlite_compress_block (inbuf, inlen, outbuf, ZLITE_BLOCK_MAX_COMPRESSED_LEN(inlen), zstr->workmem); | |
+ | |
+ if (inbuf == stream->next_in) { | |
+ stream->next_in += inlen; | |
+ stream->next_out += inlen; | |
+ } else { | |
+ zstr->inlen = 0; | |
+ zstr->inpos = 0; | |
+ } | |
+ | |
+ if (outbuf == stream->next_out) { | |
+ stream->next_out += outlen; | |
+ stream->avail_out -= outlen; | |
+ } else { | |
+ copy_size = MIN(outlen, stream->avail_out); | |
+ memcpy (stream->next_out, outbuf, copy_size); | |
+ stream->avail_out -= copy_size; | |
+ stream->next_out += copy_size; | |
+ if (copy_size == outlen) { | |
+ zstr->outlen = 0; | |
+ zstr->outpos = 0; | |
+ | |
+ return SQUASH_OK; | |
+ } else { | |
+ zstr->outlen = outlen; | |
+ zstr->outpos = copy_size; | |
+ | |
+ return SQUASH_PROCESSING; | |
+ } | |
+ } | |
+ | |
+ progress = true; | |
+ } | |
+ | |
+ return (stream->avail_in > 0) ? (progress ? SQUASH_PROCESSING : SQUASH_FAILED) : SQUASH_OK; | |
+} | |
+ | |
+static SquashStatus | |
+squash_zlite_decompress_stream (SquashStream* stream) { | |
+ SquashZliteStream* zstr = (SquashZliteStream*) stream; | |
+ size_t copy_size = 0; | |
+ bool progress = false; | |
+ | |
+ /* Try to clear the output buffer */ | |
+ if (zstr->outlen > 0) { | |
+ copy_size = MIN(stream->avail_out, zstr->outlen - zstr->outpos); | |
+ memcpy (stream->next_out, zstr->outbuf + zstr->outpos, copy_size); | |
+ stream->avail_out -= copy_size; | |
+ stream->next_out += copy_size; | |
+ zstr->outpos += copy_size; | |
+ if (zstr->outpos == zstr->outlen) { | |
+ zstr->outlen = 0; | |
+ zstr->outpos = 0; | |
+ } | |
+ | |
+ if (copy_size > 0) { | |
+ return (zstr->outlen != 0 || stream->avail_in > 0) ? SQUASH_PROCESSING : SQUASH_OK; | |
+ } else { | |
+ return SQUASH_PROCESSING; | |
+ } | |
+ } | |
+ | |
+ if (stream->avail_in == 0) { | |
+ return SQUASH_OK; | |
+ } | |
+ | |
+ /* Read header */ | |
+ if (zstr->hdrpos != ZLITE_BLOCK_HEADER_LEN) { | |
+ copy_size = MIN(stream->avail_in, ZLITE_BLOCK_HEADER_LEN - zstr->hdrpos); | |
+ memcpy (zstr->hdr + zstr->hdrpos, stream->next_in, copy_size); | |
+ zstr->hdrpos += copy_size; | |
+ stream->avail_in -= copy_size; | |
+ stream->next_in += copy_size; | |
+ progress = true; | |
+ | |
+ if (zstr->hdrpos == ZLITE_BLOCK_HEADER_LEN) { | |
+ zstr->inlen = zlite_parse_block_header (zstr->hdr, &(zstr->rlen)); | |
+ } else { | |
+ return SQUASH_OK; | |
+ } | |
+ } | |
+ | |
+ /* Fill the input buffer. */ | |
+ if ((zstr->inpos > 0) || (stream->avail_in < zstr->inlen)) { | |
+ copy_size = MIN(stream->avail_in, zstr->inlen - zstr->inpos); | |
+ if (zstr->inbuf == NULL) { | |
+ zstr->inbuf = (unsigned char*) malloc (ZLITE_BLOCK_MAX_COMPRESSED_LEN(ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)); | |
+ } | |
+ memcpy (zstr->inbuf + zstr->inpos, stream->next_in, copy_size); | |
+ stream->next_in += copy_size; | |
+ stream->avail_in -= copy_size; | |
+ zstr->inpos += copy_size; | |
+ progress = true; | |
+ } | |
+ | |
+ /* Perform the decompression */ | |
+ if (((zstr->inpos) > 0 && (zstr->inpos == zstr->inlen)) || ((zstr->inpos == 0) && (stream->avail_in == zstr->inlen))) { | |
+ unsigned char* outbuf; | |
+ const unsigned char* inbuf; | |
+ | |
+ if (stream->avail_out >= ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN) { | |
+ outbuf = stream->next_out; | |
+ } else { | |
+ if (zstr->outbuf == NULL) { | |
+ zstr->outbuf = (unsigned char*) malloc (ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN); | |
+ if (zstr->outbuf == NULL) { | |
+ return SQUASH_MEMORY; | |
+ } | |
+ } | |
+ outbuf = zstr->outbuf; | |
+ zstr->outpos = 0; | |
+ } | |
+ | |
+ if (zstr->inpos > 0) { | |
+ inbuf = zstr->inbuf; | |
+ } else { | |
+ inbuf = stream->next_in; | |
+ } | |
+ | |
+ zstr->outlen = zlite_decompress_block ((unsigned char*) inbuf, zstr->inlen, outbuf, ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN, zstr->rlen, zstr->workmem); | |
+ | |
+ if (zstr->outlen <= 0) { | |
+ return SQUASH_FAILED; | |
+ } | |
+ | |
+ if (outbuf == stream->next_out) { | |
+ stream->next_out += zstr->outlen; | |
+ stream->avail_out -= zstr->outlen; | |
+ } else { | |
+ copy_size = MIN(zstr->outlen, stream->avail_out); | |
+ memcpy (stream->next_out, outbuf, copy_size); | |
+ stream->next_out += copy_size; | |
+ stream->avail_out -= copy_size; | |
+ if (copy_size == zstr->outlen) { | |
+ zstr->outlen = 0; | |
+ zstr->outpos = 0; | |
+ } else { | |
+ zstr->outpos = copy_size; | |
+ } | |
+ } | |
+ | |
+ if (inbuf == stream->next_in) { | |
+ stream->next_in += zstr->inlen; | |
+ stream->avail_in -= zstr->inlen; | |
+ } | |
+ | |
+ progress = true; | |
+ zstr->inpos = 0; | |
+ zstr->inlen = 0; | |
+ zstr->hdrpos = 0; | |
+ } | |
+ | |
+ return (stream->avail_in > 0) ? (progress ? SQUASH_PROCESSING : SQUASH_FAILED) : SQUASH_OK; | |
+} | |
+ | |
+static SquashStatus | |
+squash_zlite_process_stream (SquashStream* stream) { | |
+ return (stream->stream_type == SQUASH_STREAM_COMPRESS) ? | |
+ squash_zlite_compress_stream (stream, false) : | |
+ squash_zlite_decompress_stream (stream); | |
+} | |
+ | |
+static SquashStatus | |
+squash_zlite_flush_stream (SquashStream* stream) { | |
+ return (stream->stream_type == SQUASH_STREAM_COMPRESS) ? | |
+ squash_zlite_compress_stream (stream, true) : | |
+ squash_zlite_decompress_stream (stream); | |
+} | |
+ | |
+SquashStatus | |
+squash_plugin_init_codec (SquashCodec* codec, SquashCodecFuncs* funcs) { | |
+ const char* name = squash_codec_get_name (codec); | |
+ | |
+ if (strcmp ("zlite", name) == 0) { | |
+ funcs->get_max_compressed_size = squash_zlite_get_max_compressed_size; | |
+ funcs->create_stream = squash_zlite_create_stream; | |
+ funcs->process_stream = squash_zlite_process_stream; | |
+ funcs->flush_stream = squash_zlite_flush_stream; | |
+ } else { | |
+ return SQUASH_UNABLE_TO_LOAD; | |
+ } | |
+ | |
+ return SQUASH_OK; | |
+} | |
diff --git a/plugins/zlite/zlite.c b/plugins/zlite/zlite.c | |
new file mode 100644 | |
index 0000000..651818a | |
--- /dev/null | |
+++ b/plugins/zlite/zlite.c | |
@@ -0,0 +1,743 @@ | |
+/* | |
+ * zlite: | |
+ * light-weight lossless data compression utility. | |
+ * | |
+ * Copyright (C) 2012-2013 by Zhang Li <zhangli10 at baidu.com> | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of the project nor the names of its contributors | |
+ * may be used to endorse or promote products derived from this software | |
+ * without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
+ * SUCH DAMAGE. | |
+ */ | |
+ | |
+/* git-tag = 20130822 | |
+ * | |
+ * reference: | |
+ * ROLZ: | |
+ * http://www.ezcodesample.com/rolz/rolz_article.html | |
+ * POLAR-CODE: | |
+ * http://www.ezcodesample.com/prefixer/prefixer_article.html | |
+ */ | |
+#include <stdio.h> | |
+#include <string.h> | |
+#include <time.h> | |
+#include <math.h> | |
+#include <stdlib.h> | |
+ | |
+#include "zlite.h" | |
+ | |
+#ifndef _DEBUG /* enable debug? */ | |
+#define _DEBUG 0 | |
+#endif | |
+ | |
+#if _DEBUG | |
+#define __DEBUG_LINE__(s) s | |
+#define __DEBUG_INFO__(...) \ | |
+ (fprintf(stderr, "__debug: "), \ | |
+ fprintf(stderr, __VA_ARGS__), \ | |
+ fprintf(stderr, "\n")) | |
+ | |
+static int count_match; | |
+static int count_lastchar; | |
+static int count_literal; | |
+ | |
+static int count_match_calls; | |
+static int count_match_items; | |
+static int count_memaccess; | |
+static int count_update_match_len; | |
+static int count_entropy_byte; | |
+ | |
+static void __debug_on_destroy__() __attribute__((__destructor__)); | |
+static void __debug_on_destroy__() { | |
+ __DEBUG_INFO__(""); | |
+ __DEBUG_INFO__("count_match: %d", count_match); | |
+ __DEBUG_INFO__("count_lastchar: %d", count_lastchar); | |
+ __DEBUG_INFO__("count_literal: %d", count_literal); | |
+ __DEBUG_INFO__(""); | |
+ __DEBUG_INFO__("count_match_calls: %d", count_match_calls); | |
+ __DEBUG_INFO__("count_match_items: %d", count_match_items); | |
+ __DEBUG_INFO__("count_memaccess: %d", count_memaccess); | |
+ __DEBUG_INFO__("count_update_match_len: %d", count_update_match_len); | |
+ __DEBUG_INFO__(""); | |
+ __DEBUG_INFO__("count_entropy_byte: %d", count_entropy_byte); | |
+ return; | |
+} | |
+ | |
+#else /* _DEBUG */ | |
+#define __DEBUG_LINE__(s) | |
+#define __DEBUG_INFO__(...) | |
+#endif | |
+ | |
+#if !defined(ZLITE_LIBRARY) | |
+static clock_t clock_start; | |
+static clock_t clock_during_rolz = 0; | |
+static clock_t clock_during_polar = 0; | |
+#define ZLITE_EXECUTABLE_ONLY(expr) expr | |
+#else | |
+#define ZLITE_EXECUTABLE_ONLY(expr) | |
+#endif /* !defined(ZLITE_LIBRARY) */ | |
+ | |
+#if !defined(ZLITE_LIBRARY) && (defined(__MINGW32__) || defined(__MINGW64__)) | |
+#include <fcntl.h> | |
+#include <io.h> | |
+ | |
+int ma_n(int argc, char** argv); | |
+int main(int argc, char** argv) { /* set stdio to binary mode for windows */ | |
+ setmode(fileno(stdin), O_BINARY); | |
+ setmode(fileno(stdout), O_BINARY); | |
+ return ma_n(argc, argv); | |
+} | |
+#define main ma_n | |
+#endif | |
+ | |
+#define __cache_aligned(name) __attribute__((aligned(64)))(name) | |
+ | |
+/******************************************************************************* | |
+ * POLAR Coder | |
+ ******************************************************************************/ | |
+#define POLAR_SYMBOLS 1024 /* should be even */ | |
+#define POLAR_MAXLEN 15 /* should be < 16 -- for packing two length values into a byte */ | |
+ | |
+#define m_round_down(x) while((x)&(-(x)^(x))) { (x) &= (-(x)^(x)); } | |
+#define m_round_up(x) while((x)&(-(x)^(x))) { (x) &= (-(x)^(x)); } (x) <<= 1; | |
+#define m_int_swap(x, y) {int (_)=(x); (x)=(y); (y)=(_);} | |
+ | |
+static int polar_make_leng_table(const unsigned int* freq_table, unsigned int* leng_table) { | |
+ int symbols[POLAR_SYMBOLS]; | |
+ int i; | |
+ int s; | |
+ int total; | |
+ int shift = 0; | |
+ | |
+ memcpy(leng_table, freq_table, POLAR_SYMBOLS * sizeof(int)); | |
+ | |
+MakeTablePass: | |
+ /* sort symbols */ | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ symbols[i] = i; | |
+ } | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { /* simple gnome sort */ | |
+ if(i > 0 && leng_table[symbols[i - 1]] < leng_table[symbols[i]]) { | |
+ m_int_swap(symbols[i - 1], symbols[i]); | |
+ i -= 2; | |
+ } | |
+ } | |
+ | |
+ /* calculate total frequency */ | |
+ total = 0; | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ total += leng_table[i]; | |
+ } | |
+ | |
+ /* run */ | |
+ m_round_up(total); | |
+ s = 0; | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ m_round_down(leng_table[i]); | |
+ s += leng_table[i]; | |
+ } | |
+ while(s < total) { | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ if(s + leng_table[symbols[i]] <= total) { | |
+ s += leng_table[symbols[i]]; | |
+ leng_table[symbols[i]] *= 2; | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* get code length */ | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ s = 2; | |
+ if(leng_table[i] > 0) { | |
+ while((total / leng_table[i]) >> s != 0) { | |
+ s += 1; | |
+ } | |
+ leng_table[i] = s - 1; | |
+ } else { | |
+ leng_table[i] = 0; | |
+ } | |
+ | |
+ /* code length too long -- scale and rebuild table */ | |
+ if(leng_table[i] > POLAR_MAXLEN) { | |
+ shift += 1; | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ if((leng_table[i] = freq_table[i] >> shift) == 0 && freq_table[i] > 0) { | |
+ leng_table[i] = 1; | |
+ } | |
+ } | |
+ goto MakeTablePass; | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static int polar_make_code_table(const unsigned int* leng_table, unsigned int* code_table) { | |
+ int i; | |
+ int s; | |
+ int t1; | |
+ int t2; | |
+ int code = 0; | |
+ | |
+ memset(code_table, 0, POLAR_SYMBOLS * sizeof(int)); | |
+ | |
+ /* make code for each symbol */ | |
+ for(s = 1; s <= POLAR_MAXLEN; s++) { | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ if(leng_table[i] == s) { | |
+ code_table[i] = code; | |
+ code += 1; | |
+ } | |
+ } | |
+ code *= 2; | |
+ } | |
+ | |
+ /* reverse each code */ | |
+ for(i = 0; i < POLAR_SYMBOLS; i++) { | |
+ t1 = 0; | |
+ t2 = leng_table[i] - 1; | |
+ while(t1 < t2) { | |
+ code_table[i] ^= (1 & (code_table[i] >> t1)) << t2; | |
+ code_table[i] ^= (1 & (code_table[i] >> t2)) << t1; | |
+ code_table[i] ^= (1 & (code_table[i] >> t1)) << t2; | |
+ t1++; | |
+ t2--; | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static int polar_make_decode_table( | |
+ const unsigned int* leng_table, | |
+ const unsigned int* code_table, unsigned short* decode_table) { | |
+ int i; | |
+ int c; | |
+ | |
+ memset(decode_table, -1, sizeof(unsigned short) << POLAR_MAXLEN); | |
+ | |
+ for(c = 0; c < POLAR_SYMBOLS; c++) { | |
+ if(leng_table[c] > 0) { | |
+ for(i = 0; i + code_table[c] < (1 << POLAR_MAXLEN); i += (1 << leng_table[c])) { | |
+ decode_table[i + code_table[c]] = leng_table[c] * POLAR_SYMBOLS + c; | |
+ } | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
+/******************************************************************************* | |
+ * ROLZ | |
+ ******************************************************************************/ | |
+#define ROLZ_BUCKET_SIZE 32768 | |
+#define MATCH_IDX_SIZE 15 /* make element of rolz_table[] 64 Bytes */ | |
+#define MATCH_LEN_MIN 2 | |
+#define MATCH_LEN_MAX 52 /* 256+(52-2)*15+14 = 1020 < 1023 */ | |
+ | |
+#define m_pack_literal(byte) ((unsigned short)(byte)) | |
+#define m_pack_match(mi, ml) ((unsigned short)(256 + ((ml)-MATCH_LEN_MIN)*MATCH_IDX_SIZE+(mi))) | |
+#define m_pack_last() ((unsigned short)(POLAR_SYMBOLS - 1)) | |
+ | |
+#define m_ispack_literal(sh) ((sh) < 256) | |
+#define m_ispack_match(sh) ((sh) >= 256 && (sh) < (POLAR_SYMBOLS - 1)) | |
+#define m_ispack_last(sh) ((sh) == (POLAR_SYMBOLS - 1)) | |
+ | |
+#define m_unpack_literal(sh) ((unsigned char)(sh)) | |
+#define m_unpack_match_idx(sh) (((sh) - 256) % MATCH_IDX_SIZE) | |
+#define m_unpack_match_len(sh) (((sh) - 256) / MATCH_IDX_SIZE + MATCH_LEN_MIN) | |
+/* | |
+ * code: | |
+ * 0x0000 - 0x00ff = literal char | |
+ * 0x0100 - 0x03fe = match | |
+ * 00x3ff = literal (last-char matched) | |
+ */ | |
+static unsigned short context2 = 0; | |
+static unsigned short context3 = 0; | |
+ | |
+static const unsigned char __cache_aligned(mod15_table)[] = { /* MATCH_IDX_SIZE=15 */ | |
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | |
+}; | |
+#define m_rolz_item(x, n) rolz_table[(x)].m_item[mod15_table[rolz_table[(x)].m_head + (n)]] | |
+ | |
+/* last-char table */ | |
+static unsigned char lastchar[65536]; | |
+ | |
+/* rolz table */ | |
+struct rolz_item_st { | |
+ unsigned m_pos: 24; | |
+ unsigned m_cache: 8; | |
+}; | |
+struct rolz_bucket_st { | |
+ struct rolz_item_st m_item[MATCH_IDX_SIZE]; | |
+ unsigned m_head; | |
+}; | |
+struct rolz_bucket_st __cache_aligned(rolz_table)[ROLZ_BUCKET_SIZE]; | |
+ | |
+#define UPDATE_CACHE_CHAR 0x01 | |
+#define UPDATE_ROLZ 0x02 | |
+#define UPDATE_CONTEXT3 0x04 | |
+ | |
+#define m_make_context3(context2, ch) (((context2) * 337 + (ch)) % ROLZ_BUCKET_SIZE) | |
+#define m_rolz_check(ptr) (((ptr)[0] * 113 + (ptr)[1]) & 0xff) | |
+ | |
+static void rolz_update_context(unsigned char* buf, int pos, int update) { | |
+ int new_head; | |
+ | |
+ if(update & UPDATE_ROLZ) { /* update rolz table */ | |
+ new_head = mod15_table[rolz_table[context3].m_head + (MATCH_IDX_SIZE - 1)]; | |
+ rolz_table[context3].m_head = new_head; | |
+ rolz_table[context3].m_item[new_head].m_pos = pos; | |
+ if(update & UPDATE_CACHE_CHAR) { | |
+ rolz_table[context3].m_item[new_head].m_cache = m_rolz_check(buf + pos); | |
+ } | |
+ } | |
+ if(update & UPDATE_CONTEXT3) { /* update context */ | |
+ context3 = m_make_context3(context2, buf[pos]); | |
+ } | |
+ lastchar[context2] = buf[pos]; /* update last-char table */ | |
+ context2 <<= 8; | |
+ context2 |= buf[pos]; | |
+ return; | |
+} | |
+ | |
+static int find_common_length(unsigned char* buf1, unsigned char* buf2, int maxlen) { | |
+ unsigned char* p1 = buf1; | |
+ unsigned char* p2 = buf2; | |
+ | |
+ while((maxlen--) > 0 && *p1 == *p2) { | |
+ p1++; | |
+ p2++; | |
+ } | |
+ return p1 - buf1; | |
+} | |
+ | |
+static int match(unsigned char* buf, unsigned int pos, unsigned int context3, int* pidx, int* plen) { | |
+ int i; | |
+ int match_idx = -1; | |
+ int match_len = MATCH_LEN_MIN - 1; | |
+ int match_len_item; | |
+ | |
+ __DEBUG_LINE__( | |
+ count_match_calls += 1; | |
+ ); | |
+ for(i = 0; i < MATCH_IDX_SIZE; i++) { | |
+ struct rolz_item_st* item = &m_rolz_item(context3, i); | |
+ | |
+ __DEBUG_LINE__( | |
+ count_match_items += 1; | |
+ count_memaccess += (item->m_cache == m_rolz_check(&buf[pos])); | |
+ ); | |
+ | |
+ /* find a longer match? */ | |
+ if(item->m_cache == m_rolz_check(buf + pos)) { | |
+ if(buf[pos + match_len] == buf[item->m_pos + match_len]) { | |
+ if((match_len_item = find_common_length(buf + pos, buf + item->m_pos, MATCH_LEN_MAX)) > match_len) { | |
+ __DEBUG_LINE__( | |
+ count_update_match_len += 1; | |
+ ); | |
+ match_len = match_len_item; | |
+ match_idx = i; | |
+ if(match_len == MATCH_LEN_MAX) { /* no need to find longer match */ | |
+ break; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ } | |
+ if(match_len >= MATCH_LEN_MIN) { | |
+ *pidx = match_idx; | |
+ *plen = match_len; | |
+ return 1; | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static int rolz_encode(unsigned char* ibuf, unsigned short* obuf, int ilen) { | |
+ int olen = 0; | |
+ int pos = 0; | |
+ int match_idx; | |
+ int match_len; | |
+ | |
+ memset(rolz_table, 0, sizeof(rolz_table)); | |
+ context2 = 0; | |
+ context3 = 0; | |
+ | |
+ while(pos + MATCH_LEN_MAX < ilen) { | |
+ if(!match(ibuf, pos, context3, &match_idx, &match_len)) { /* find match */ | |
+ if(lastchar[context2] == ibuf[pos]) { | |
+ __DEBUG_LINE__( | |
+ count_lastchar += 1; | |
+ ); | |
+ obuf[olen++] = m_pack_last(); /* encode as last-char literal */ | |
+ } else { | |
+ __DEBUG_LINE__( | |
+ count_literal += 1; | |
+ ); | |
+ obuf[olen++] = m_pack_literal(ibuf[pos]); /* encode as literal */ | |
+ } | |
+ rolz_update_context(ibuf, pos++, UPDATE_CACHE_CHAR | UPDATE_ROLZ | UPDATE_CONTEXT3); | |
+ | |
+ } else { | |
+ __DEBUG_LINE__( | |
+ count_match += 1; | |
+ ); | |
+ obuf[olen++] = m_pack_match(match_idx, match_len); // encode as match | |
+ | |
+ /* update context for current pos with rolz-table updating */ | |
+ rolz_update_context(ibuf, pos++, UPDATE_CACHE_CHAR | UPDATE_ROLZ); | |
+ match_len--; | |
+ | |
+ /* update context for next pos */ | |
+ while((match_len--) > 1) { | |
+ rolz_update_context(ibuf, pos++, 0); | |
+ } | |
+ rolz_update_context(ibuf, pos++, UPDATE_CONTEXT3); | |
+ } | |
+ } | |
+ | |
+ while(pos < ilen) { | |
+ obuf[olen++] = m_pack_literal(ibuf[pos]); | |
+ pos++; | |
+ } | |
+ return olen; | |
+} | |
+ | |
+static int rolz_decode(unsigned short* ibuf, unsigned char* obuf, int ilen) { | |
+ int olen = 0; | |
+ int pos = 0; | |
+ int match_idx; | |
+ int match_len; | |
+ int match_offset; | |
+ | |
+ memset(rolz_table, 0, sizeof(rolz_table)); | |
+ context2 = 0; | |
+ context3 = 0; | |
+ | |
+ for(pos = 0; pos < ilen; pos++) { | |
+ if(m_ispack_last(ibuf[pos])) { /* last-char match */ | |
+ obuf[olen] = lastchar[context2]; | |
+ rolz_update_context(obuf, olen++, UPDATE_ROLZ | UPDATE_CONTEXT3); | |
+ | |
+ } else if(m_ispack_literal(ibuf[pos])) { /* process a literal byte */ | |
+ obuf[olen] = m_unpack_literal(ibuf[pos]); | |
+ rolz_update_context(obuf, olen++, UPDATE_ROLZ | UPDATE_CONTEXT3); | |
+ | |
+ } else { /* process a match */ | |
+ match_idx = m_unpack_match_idx(ibuf[pos]); | |
+ match_len = m_unpack_match_len(ibuf[pos]); | |
+ match_offset = olen - m_rolz_item(context3, match_idx).m_pos; | |
+ | |
+ /* update context at current pos with rolz-table updating */ | |
+ obuf[olen] = obuf[olen - match_offset]; | |
+ rolz_update_context(obuf, olen++, UPDATE_ROLZ); | |
+ match_len--; | |
+ | |
+ /* update context for next pos */ | |
+ while((match_len--) > 1) { | |
+ obuf[olen] = obuf[olen - match_offset]; | |
+ rolz_update_context(obuf, olen++, 0); | |
+ } | |
+ obuf[olen] = obuf[olen - match_offset]; | |
+ rolz_update_context(obuf, olen++, UPDATE_CONTEXT3); | |
+ } | |
+ } | |
+ return olen; | |
+} | |
+ | |
+/******************************************************************************* | |
+ * PUBLIC API | |
+ ******************************************************************************/ | |
+ | |
+#define ZLITE_RETURN_ERROR(e) return ((workmem == NULL) ? (free(tbuf), e) : e); | |
+ | |
+int zlite_compress_block(unsigned char* ibuf, int ilen, unsigned char* obuf, int olen, void* workmem) { | |
+ unsigned short* tbuf; | |
+ unsigned int freq_table[POLAR_SYMBOLS] = { 0, }; | |
+ unsigned int leng_table[POLAR_SYMBOLS]; | |
+ unsigned int code_table[POLAR_SYMBOLS]; | |
+ int rlen; | |
+ int i; | |
+ unsigned int code_buf; | |
+ unsigned int code_len; | |
+ int outlen = 8; | |
+ ZLITE_EXECUTABLE_ONLY(clock_t checkpoint); | |
+ | |
+ if (olen < 8 || ilen > ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN) { | |
+ return -1; | |
+ } | |
+ tbuf = workmem != NULL ? workmem : (unsigned short*) malloc (ZLITE_WORK_MEM_LEN); | |
+ | |
+ /* rolz-encode */ | |
+ ZLITE_EXECUTABLE_ONLY(checkpoint = clock()); | |
+ { | |
+ rlen = rolz_encode(ibuf, tbuf, ilen); | |
+ } | |
+ ZLITE_EXECUTABLE_ONLY(clock_during_rolz += clock() - checkpoint); | |
+ | |
+ /* polar-encode */ | |
+ ZLITE_EXECUTABLE_ONLY(checkpoint = clock()); | |
+ { | |
+ code_buf = 0; | |
+ code_len = 0; | |
+ | |
+ for(i = 0; i < rlen; i++) { | |
+ freq_table[tbuf[i]] += 1; | |
+ } | |
+ polar_make_leng_table(freq_table, leng_table); | |
+ polar_make_code_table(leng_table, code_table); | |
+ | |
+ /* debug: compute entropy */ | |
+ for(i = 0; i < 1024; i++) { | |
+ if(freq_table[i]) { | |
+ __DEBUG_LINE__( | |
+ count_entropy_byte -= freq_table[i] * log2((double)freq_table[i] / rlen) / 8; | |
+ ); | |
+ } | |
+ } | |
+ | |
+ /* write length table */ | |
+ for(i = 0; i < POLAR_SYMBOLS; i += 2) { | |
+ if(outlen == olen) { | |
+ ZLITE_RETURN_ERROR(-1); | |
+ } | |
+ obuf[outlen++] = leng_table[i] * 16 + leng_table[i + 1]; | |
+ } | |
+ | |
+ /* encode */ | |
+ for(i = 0; i < rlen; i++) { | |
+ code_buf += code_table[tbuf[i]] << code_len; | |
+ code_len += leng_table[tbuf[i]]; | |
+ while(code_len >= 8) { | |
+ if(outlen == olen) { | |
+ ZLITE_RETURN_ERROR(-1); | |
+ } | |
+ obuf[outlen++] = code_buf % 256; | |
+ code_buf /= 256; | |
+ code_len -= 8; | |
+ } | |
+ } | |
+ | |
+ if(code_len > 0) { | |
+ if(outlen == olen) { | |
+ ZLITE_RETURN_ERROR(-1); | |
+ } | |
+ obuf[outlen++] = code_buf; | |
+ code_buf = 0; | |
+ code_len = 0; | |
+ } | |
+ } | |
+ ZLITE_EXECUTABLE_ONLY(clock_during_polar += clock() - checkpoint); | |
+ | |
+ outlen -= 8; | |
+ obuf[0] = (unsigned char) (rlen % 256); | |
+ obuf[1] = (unsigned char) (outlen % 256); | |
+ obuf[2] = (unsigned char) (rlen / 256 % 256); | |
+ obuf[3] = (unsigned char) (outlen / 256 % 256); | |
+ obuf[4] = (unsigned char) (rlen / 256 / 256 % 256); | |
+ obuf[5] = (unsigned char) (outlen / 256 / 256 % 256); | |
+ obuf[6] = (unsigned char) (rlen / 256 / 256 / 256 % 256); | |
+ obuf[7] = (unsigned char) (outlen / 256 / 256 / 256 % 256); | |
+ outlen += 8; | |
+ | |
+ if (workmem == NULL) { | |
+ free(tbuf); | |
+ } | |
+ | |
+ return outlen; | |
+} | |
+ | |
+int zlite_parse_block_header(unsigned char header[ZLITE_BLOCK_HEADER_LEN], int* rlen) { | |
+ int olen; | |
+ | |
+ *rlen = header[0]; | |
+ olen = header[1]; | |
+ *rlen += ((int) header[2]) * 256; | |
+ olen += ((int) header[3]) * 256; | |
+ *rlen += ((int) header[4]) * 65536; | |
+ olen += ((int) header[5]) * 65536; | |
+ *rlen += ((int) header[6]) * 16777216; | |
+ olen += ((int) header[7]) * 16777216; | |
+ | |
+ return olen; | |
+} | |
+ | |
+int zlite_decompress_block(unsigned char* ibuf, int ilen, unsigned char* obuf, int olen, int rlen, void* workmem) { | |
+ unsigned short* tbuf; | |
+ unsigned int leng_table[POLAR_SYMBOLS]; | |
+ unsigned int code_table[POLAR_SYMBOLS]; | |
+ unsigned short decode_table[1 << POLAR_MAXLEN]; | |
+ int i; | |
+ int rpos = 0; | |
+ int ipos = 0; | |
+ int code_buf = 0; | |
+ int code_len = 0; | |
+ ZLITE_EXECUTABLE_ONLY(clock_t checkpoint); | |
+ | |
+ tbuf = workmem != NULL ? workmem : (unsigned short*) malloc (ZLITE_WORK_MEM_LEN); | |
+ | |
+ /* polar-decode */ | |
+ ZLITE_EXECUTABLE_ONLY(checkpoint = clock()); | |
+ { | |
+ /* read length table */ | |
+ for(i = 0; i < POLAR_SYMBOLS; i += 2) { | |
+ if (ipos == ilen) { | |
+ ZLITE_RETURN_ERROR(-1); | |
+ } | |
+ leng_table[i] = ibuf[ipos] / 16; | |
+ leng_table[i + 1] = ibuf[ipos] % 16; | |
+ ipos++; | |
+ } | |
+ | |
+ /* decode */ | |
+ polar_make_code_table(leng_table, code_table); | |
+ polar_make_decode_table(leng_table, code_table, decode_table); | |
+ | |
+ while(rpos < rlen) { | |
+ while(ipos < ilen && code_len < POLAR_MAXLEN) { | |
+ if (ipos == ilen) { | |
+ fprintf (stderr, "Overflow: %d of %d\n", ipos, ilen); | |
+ ZLITE_RETURN_ERROR(-1); | |
+ } | |
+ code_buf += ibuf[ipos++] << code_len; | |
+ code_len += 8; | |
+ } | |
+ i = decode_table[code_buf % (1 << POLAR_MAXLEN)]; | |
+ code_buf >>= i / POLAR_SYMBOLS; | |
+ code_len -= i / POLAR_SYMBOLS; | |
+ tbuf[rpos++] = i % POLAR_SYMBOLS; | |
+ } | |
+ } | |
+ ZLITE_EXECUTABLE_ONLY(clock_during_polar += clock() - checkpoint); | |
+ | |
+ /* rolz-decode */ | |
+ ZLITE_EXECUTABLE_ONLY(checkpoint = clock()); | |
+ { | |
+ ipos = rolz_decode(tbuf, obuf, rlen); | |
+ } | |
+ ZLITE_EXECUTABLE_ONLY(clock_during_rolz += clock() - checkpoint); | |
+ | |
+ if (workmem == NULL) { | |
+ free(tbuf); | |
+ } | |
+ | |
+ return ipos; | |
+} | |
+ | |
+/******************************************************************************* | |
+ * MAIN | |
+ ******************************************************************************/ | |
+#ifndef ZLITE_LIBRARY | |
+static void print_result(size_t size_src, size_t size_dst, int encode) { | |
+ fprintf(stderr, (encode ? | |
+ "encode: %u => %u, time=%.3f sec\n" : | |
+ "decode: %u <= %u, time=%.3f sec\n"), | |
+ size_src, | |
+ size_dst, | |
+ (clock() - clock_start) / (double)CLOCKS_PER_SEC); | |
+ | |
+ fprintf(stderr, "\ttime_rolz: %.3f sec\n", clock_during_rolz / (double)CLOCKS_PER_SEC); | |
+ fprintf(stderr, "\ttime_polar: %.3f sec\n", clock_during_polar / (double)CLOCKS_PER_SEC); | |
+ return; | |
+} | |
+ | |
+int main(int argc, char** argv) { | |
+ static unsigned short workmem[ZLITE_WORK_MEM_LEN]; | |
+ static unsigned char cbuf[ZLITE_BLOCK_MAX_COMPRESSED_LEN(ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN)]; | |
+ size_t size_src = 0; | |
+ size_t size_dst = 0; | |
+ int ilen; | |
+ int rlen; | |
+ int olen; | |
+ | |
+ clock_start = clock(); | |
+ | |
+ /* welcome message */ | |
+ fprintf(stderr, "zlite:\n"); | |
+ fprintf(stderr, " light-weight lossless data compression utility\n"); | |
+ fprintf(stderr, " by Zhang Li <zhangli10 at baidu.com>\n"); | |
+ fprintf(stderr, "\n"); | |
+ | |
+ /* zlite <e/d> __argv2__ __argv3__ */ | |
+ if(argc == 4) { | |
+ if(freopen(argv[2], "rb", stdin) == NULL) { | |
+ fprintf(stderr, "error: cannot open file '%s' for read.\n", argv[2]); | |
+ return -1; | |
+ } | |
+ if(freopen(argv[3], "wb", stdout) == NULL) { | |
+ fprintf(stderr, "error: cannot open file '%s' for write.\n", argv[3]); | |
+ return -1; | |
+ } | |
+ argc = 2; | |
+ } | |
+ | |
+ /* zlite <e/d> __argv2__ (stdout) */ | |
+ if(argc == 3) { | |
+ if(freopen(argv[2], "rb", stdin) == NULL) { | |
+ fprintf(stderr, "error: cannot open file '%s' for read.\n", argv[2]); | |
+ return -1; | |
+ } | |
+ argc = 2; | |
+ } | |
+ | |
+ /* zlite <e/d> (stdin) (stdout) */ | |
+ if(argc == 2 && strcmp(argv[1], "e") == 0) { | |
+ while((ilen = fread(cbuf, 1, ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN, stdin)) > 0) { | |
+ fprintf (stderr, "zlite_compress_block (%p, %d, %p, %d);\n", cbuf, ilen, cbuf, sizeof(cbuf)); | |
+ olen = zlite_compress_block (cbuf, ilen, cbuf, sizeof(cbuf), workmem); | |
+ fwrite(cbuf, 1, olen, stdout); | |
+ | |
+ size_dst += olen; | |
+ size_src += ilen; | |
+ } | |
+ print_result(size_src, size_dst, 1); | |
+ return 0; | |
+ } | |
+ | |
+ if(argc == 2 && strcmp(argv[1], "d") == 0) { | |
+ while ((fread(cbuf, 1, ZLITE_BLOCK_HEADER_LEN, stdin) == ZLITE_BLOCK_HEADER_LEN) && | |
+ !feof(stdin) && !ferror(stdin)) { | |
+ olen = zlite_parse_block_header (cbuf, &rlen); | |
+ fprintf (stderr, "compressed data length: %d\n", olen); | |
+ if(olen < sizeof(cbuf) && fread(cbuf, 1, olen, stdin) == olen) { | |
+ ilen = zlite_decompress_block(cbuf, olen, cbuf, sizeof(cbuf), rlen, workmem); | |
+ if(ilen > 0) { | |
+ fwrite(cbuf, 1, ilen, stdout); | |
+ size_src += ilen; | |
+ size_dst += olen + sizeof(rlen) + sizeof(olen); | |
+ } | |
+ } else { | |
+ break; | |
+ } | |
+ } | |
+ print_result(size_src, size_dst, 0); | |
+ return 0; | |
+ } | |
+ | |
+ /* help message */ | |
+ fprintf(stderr, "usage:\n"); | |
+ fprintf(stderr, " zlite e source target\n"); | |
+ fprintf(stderr, " zlite d source target\n"); | |
+ fprintf(stderr, " * source: default to stdin\n"); | |
+ fprintf(stderr, " * target: default to stdout\n"); | |
+ return -1; | |
+} | |
+#endif /* defined(ZLITE_LIBRARY) */ | |
diff --git a/plugins/zlite/zlite.codecs b/plugins/zlite/zlite.codecs | |
new file mode 100644 | |
index 0000000..0c688e1 | |
--- /dev/null | |
+++ b/plugins/zlite/zlite.codecs | |
@@ -0,0 +1 @@ | |
+[zlite] | |
diff --git a/plugins/zlite/zlite.h b/plugins/zlite/zlite.h | |
new file mode 100644 | |
index 0000000..c6ad3df | |
--- /dev/null | |
+++ b/plugins/zlite/zlite.h | |
@@ -0,0 +1,110 @@ | |
+/* | |
+ * zlite: | |
+ * light-weight lossless data compression utility. | |
+ * | |
+ * Copyright (C) 2012-2013 by Zhang Li <zhangli10 at baidu.com> | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of the project nor the names of its contributors | |
+ * may be used to endorse or promote products derived from this software | |
+ * without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
+ * SUCH DAMAGE. | |
+ */ | |
+ | |
+#ifndef _ZLITE_H_ | |
+#define _ZLITE_H_ | |
+ | |
+#ifdef __cplusplus | |
+extern "C" { | |
+#endif | |
+ | |
+#define ZLITE_BLOCK_HEADER_LEN 8 | |
+ | |
+/** | |
+ * The maximum uncompressed block size. If you have more data than | |
+ * this you must encode it in multiple blocks of no more than | |
+ * ZLIT_BLOCK_MAX_UNCOMPRESSED_LEN bytes. | |
+ */ | |
+#define ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN (1 << 24) | |
+ | |
+/* | |
+ * Size of the buffer which can be passed to the workmem parameter of | |
+ * zlite_compress_block and zlite_decompress_block. | |
+ */ | |
+#define ZLITE_WORK_MEM_LEN (sizeof(unsigned short) * ZLITE_BLOCK_MAX_UNCOMPRESSED_LEN) | |
+ | |
+/* | |
+ * The maximum size of a compressed block of data when the | |
+ * uncompressed data is uncompressed_len bytes long. To account for | |
+ * the worst-case scenario (random data), this is slightly longer than | |
+ * the uncompressed_len. | |
+ */ | |
+#define ZLITE_BLOCK_MAX_COMPRESSED_LEN(uncompressed_len) (ZLITE_BLOCK_HEADER_LEN + 512 + uncompressed_len + (uncompressed_len / 5)) | |
+ | |
+/* | |
+ * Compress a block of data. | |
+ * | |
+ * @param ibuf input buffer | |
+ * @param ilen length of input buffer | |
+ * @param obuf output buffer | |
+ * @param olen output buffer length | |
+ * @param workmem working memory, or NULL to malloc()/free() a | |
+ * temporary buffer internally | |
+ * @return the length of the output | |
+ */ | |
+int zlite_compress_block(unsigned char* ibuf, int ilen, unsigned char* obuf, int olen, void* workmem); | |
+ | |
+/* | |
+ * Parse a block header. | |
+ * | |
+ * The return value is the length of the compressed block. ulen is | |
+ * the length of the decompressed data. | |
+ * | |
+ * @param header the header | |
+ * @param rlen location to store the ROLZ length | |
+ * @param workmem working memory, or NULL to malloc()/free() a | |
+ * temporary buffer internally | |
+ * @return length of the compressed data | |
+ */ | |
+int zlite_parse_block_header(unsigned char header[ZLITE_BLOCK_HEADER_LEN], int* rlen); | |
+ | |
+/* | |
+ * Decompress a block of data. | |
+ * | |
+ * ilen and ibuf should have been previously determined by a call to | |
+ * zlite_parse_block_header, and must be exactly right. | |
+ * | |
+ * @param ibuf compressed block | |
+ * @param ilen length of the compressed block | |
+ * @param obuf output buffer | |
+ * @param olen length of the output buffer | |
+ * @param rlen ROLZ len | |
+ * @return lengh of the decompressed data on success, or a negative | |
+ * value on error | |
+ */ | |
+int zlite_decompress_block(unsigned char* ibuf, int ilen, unsigned char* obuf, int olen, int rlen, void* workmem); | |
+ | |
+#ifdef __cplusplus | |
+} | |
+#endif | |
+ | |
+#endif /* !defined(_ZLIB_H_) */ | |
diff --git a/plugins/zlite/zlite.md b/plugins/zlite/zlite.md | |
new file mode 100644 | |
index 0000000..4d0d43d | |
--- /dev/null | |
+++ b/plugins/zlite/zlite.md | |
@@ -0,0 +1,14 @@ | |
+# zlite Plugin # | |
+ | |
+For more information about zlite, see https://github.com/richox/zlite | |
+ | |
+## Codecs ## | |
+ | |
+- **zlite** — zlite data. | |
+ | |
+## License ## | |
+ | |
+The zlite plugin is licensed under the [MIT | |
+License](http://opensource.org/licenses/MIT), and zlite is licensed | |
+under a [3-clause BSD | |
+License](http://opensource.org/licenses/BSD-3-Clause). | |
-- | |
1.8.3.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment