Skip to content

Instantly share code, notes, and snippets.

@nemequ
Created October 31, 2013 05:14
Show Gist options
  • Save nemequ/7244649 to your computer and use it in GitHub Desktop.
Save nemequ/7244649 to your computer and use it in GitHub Desktop.
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