summaryrefslogtreecommitdiff
path: root/src/tbdecode.h
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2016-06-01 18:58:58 -0700
committerScott Gasch <[email protected]>2016-06-01 18:58:58 -0700
commit3fd43cd5fcb22bb65bf2a92a25d95d801b11c9e0 (patch)
tree9b6443235d16ba17f094a1a1c7ae53d2bcb9267b /src/tbdecode.h
Initial checkin for typhoon chess engine.
Diffstat (limited to 'src/tbdecode.h')
-rw-r--r--src/tbdecode.h1038
1 files changed, 1038 insertions, 0 deletions
diff --git a/src/tbdecode.h b/src/tbdecode.h
new file mode 100644
index 0000000..22bd5a0
--- /dev/null
+++ b/src/tbdecode.h
@@ -0,0 +1,1038 @@
+#ifndef TBDECODE
+#define TBDECODE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifndef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC CLK_TCK
+#endif
+
+/* ---------------------------- Error codes --------------------------- */
+/* ----------- */
+
+#define COMP_ERR_NONE 0 /* everything is OK */
+#define COMP_ERR_READ 2 /* input file read error */
+#define COMP_ERR_NOMEM 5 /* no enough memory */
+#define COMP_ERR_BROKEN 6 /* damaged compressed data */
+#define COMP_ERR_PARAM 7 /* incorrect function parameter */
+#define COMP_ERR_INTERNAL 9 /* everything else is internal error */
+ /* hopefully it should never happen */
+
+/* Almost all functions listed further return one as its result on of */
+/* codes given above: if no error occured then COMP_ERR_NONE (i.e. 0) */
+/* is returned, otherwise functions return error code plus number of */
+/* line in "comp.c" where the error was detected multiplied by 256; */
+/* line number may be used for exact specification of a place where */
+/* error was detected thus making debugging slightly simpler. */
+/* */
+/* Thus, "(code & 0xff)" gives proper error code, and "(code >> 8)" */
+/* gives number of line where the error was raised. */
+
+/* -------------------------------------------------------------------- */
+/* */
+/* Compress/decompress some chess tables */
+/* */
+/* Copyright (c) 1991--1998 Andrew Kadatch */
+/* */
+/* The Limited-Reference variant of Lempel-Ziv algorithm implemented */
+/* here was first described in my B.Sc. thesis "Efficient algorithms */
+/* for image compression", Novosibirsk State University, 1992, and */
+/* cannot be used in any product distributed in Russia or CIS without */
+/* written permission from the author. */
+/* */
+/* Most of the code listed below is significantly simplified code from */
+/* the PRS data compression library and therefore it should not be used */
+/* in any product (software or hardware, commercial or not, and so on) */
+/* without written permission from the author. */
+/* */
+/* -------------------------------------------------------------------- */
+
+/* ---------------------------- Debugging ----------------------------- */
+/* --------- */
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#if DEBUG
+#define assert(cond) ((cond) ? (void) 0 : _local_assert (__LINE__))
+static void _local_assert(int lineno)
+{
+ fprintf(stderr, "assertion at line %u failed\n", lineno);
+ exit(33);
+}
+
+#define debug(x) x
+#define dprintf(x) printf x
+#else
+#if !defined (assert)
+#define assert(cond) ((void) 0)
+#endif
+#define debug(x) ((void) 0)
+#define dprintf(x) ((void) 0)
+#endif
+
+/* mob_pach */
+#ifndef __cplusplus
+int cbEGTBCompBytes = 0;
+#else
+extern "C" {
+ int cbEGTBCompBytes = 0;
+}
+#endif
+/* --------------------- Constants, types, etc. ----------------------- */
+/* ---------------------- */
+#define MIN_BLOCK_BITS 8 /* LOG2 (min size of block to compress) */
+#define MAX_BLOCK_BITS 16 /* LOG2 (max size of block to compress) */
+ /* max. integer we can take LOG2 by table */
+#define MAX_BITS_HALF ((MAX_BLOCK_BITS + 1) >> 1)
+#define MAX_BITS (MAX_BITS_HALF * 2)
+/* assume that integer is at least 32 bits wide */
+#ifndef uint
+#define uint unsigned
+#endif
+#ifndef uchar
+#define uchar unsigned char
+#endif
+#define HEADER_SIZE 80 /* number of reserved bytes */
+#define STOP_SEARCH_LENGTH 256 /* terminate search if match */
+ /* length exceeds that value */
+#define MAX_LENGTH_BITS 5
+#define MAX_LENGTH (1 << MAX_LENGTH_BITS)
+#define LONG_BITS 1
+#define LONG_LENGTH (MAX_BLOCK_BITS - LONG_BITS)
+#define LONG_QUICK (MAX_LENGTH - LONG_LENGTH)
+#if LONG_LENGTH > (MAX_BLOCK_BITS - LONG_BITS)
+# undef LONG_LENGTH
+# define LONG_LENGTH (MAX_BLOCK_BITS - LONG_BITS)
+#endif
+#if LONG_LENGTH >= MAX_LENGTH || LONG_LENGTH <= 0
+#error LONG_LENGTH is out of range
+#endif
+#if LONG_BITS <= 0
+#error LONG_BITS must be positive
+#endif
+#define DELTA (LONG_BITS + LONG_QUICK - 1)
+#if (MAX_LENGTH - 1) - (LONG_LENGTH - LONG_BITS) != DELTA
+#error Hmmm
+#endif
+#define MAX_DISTANCES 24
+#define LOG_MAX_DISTANCES 6 /* see check below */
+#if MAX_DISTANCES > (1 << LOG_MAX_DISTANCES)
+#error MAX_DISTANCES should not exceed (1 << LOG_MAX_DISTANCES)
+#endif
+#define ALPHABET_SIZE (256 + (MAX_DISTANCES << MAX_LENGTH_BITS))
+#define MAX_ALPHABET ALPHABET_SIZE /* max. alphabet handled by */
+ /* Huffman coding routines */
+#define USE_CRC32 1
+/* 0 - use Fletcher's checksum, != 0 - use proper CRC32 */
+ static uchar header_title[64] =
+ "Compressed by DATACOMP v 1.0 (c) 1991--1998 Andrew Kadatch\r\n\0";
+
+#define RET(n) ((n) + __LINE__ * 256)
+
+/* ------------------------- CRC32 routines --------------------------- */
+/* -------------- */
+
+#if USE_CRC32
+
+static unsigned CRC32_table[256];
+static int CRC32_initialized = 0;
+
+static void CRC32_init(void)
+{
+ int i, j;
+ unsigned k, m = (unsigned) 0xedb88320L;
+
+ if (CRC32_initialized)
+ return;
+ for (i = 0; i < 256; ++i) {
+ k = i;
+ j = 8;
+ do {
+ if ((k & 1) != 0)
+ k >>= 1;
+ else {
+ k >>= 1;
+ k ^= m;
+ };
+ }
+ while (--j);
+ CRC32_table[i] = k;
+ }
+ CRC32_initialized = 1;
+}
+
+static unsigned CRC32(uchar * p, int n, unsigned k)
+{
+ unsigned *table = CRC32_table;
+ uchar *e = p + n;
+
+ while (p + 16 < e) {
+# define X(i) k = table[((uchar) k) ^ p[i]] ^ (k >> 8)
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ X(5);
+ X(6);
+ X(7);
+ X(8);
+ X(9);
+ X(10);
+ X(11);
+ X(12);
+ X(13);
+ X(14);
+ X(15);
+# undef X
+ p += 16;
+ }
+ while (p < e)
+ k = table[((uchar) k) ^ *p++] ^ (k >> 8);
+ return (k);
+}
+
+#else
+
+#define CRC32_init()
+
+static unsigned CRC32(uchar * p, int n, unsigned k1)
+{
+ unsigned k0 = k1 & 0xffff;
+ uchar *e = p + n;
+
+ k1 = (k1 >> 16) & 0xffff;
+ while (p + 16 < e) {
+# define X(i) k0 += p[i]; k1 += k0;
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ X(5);
+ X(6);
+ X(7);
+ X(8);
+ X(9);
+ X(10);
+ X(11);
+ X(12);
+ X(13);
+ X(14);
+ X(15);
+# undef X
+ k0 = (k0 & 0xffff) + (k0 >> 16);
+ k1 = (k1 & 0xffff) + (k1 >> 16);
+ p += 16;
+ }
+ while (p < e) {
+ k0 += *p++;
+ k1 += k0;
+ }
+ k0 = (k0 & 0xffff) + (k0 >> 16);
+ k1 = (k1 & 0xffff) + (k1 >> 16);
+ k0 = (k0 & 0xffff) + (k0 >> 16);
+ k1 = (k1 & 0xffff) + (k1 >> 16);
+ assert(((k0 | k1) >> 16) == 0);
+ return (k0 + (k1 << 16));
+}
+
+#endif /* USE_CRC32 */
+
+/* ------------------------ Bit IO interface -------------------------- */
+/* ---------------- */
+
+#define BITIO_LOCALS \
+ uint _mask; \
+ int _bits; \
+ uchar *_ptr
+
+typedef struct {
+ BITIO_LOCALS;
+} bitio_t;
+
+#define BITIO_ENTER(p) do { \
+ _mask = (p)._mask; \
+ _bits = (p)._bits; \
+ _ptr = (p)._ptr; \
+} while (0)
+
+#define BITIO_LEAVE(p) do { \
+ (p)._mask = _mask; \
+ (p)._bits = _bits; \
+ (p)._ptr = _ptr; \
+} while (0)
+
+#define BIORD_START(from) do { \
+ _ptr = (uchar *) (from); \
+ _bits = sizeof (_mask); \
+ _mask = 0; \
+ do \
+ _mask = (_mask << 8) | *_ptr++; \
+ while (--_bits != 0); \
+ _bits = 16; \
+} while (0)
+
+/* read [1, 17] bits at once */
+#define BIORD(bits) \
+ (_mask >> (8 * sizeof (_mask) - (bits)))
+
+#define BIORD_MORE(bits) do { \
+ _mask <<= (bits); \
+ if ((_bits -= (bits)) <= 0) \
+ { \
+ _mask |= ((_ptr[0] << 8) + _ptr[1]) << (-_bits); \
+ _ptr += 2; _bits += 16; \
+ } \
+} while (0)
+
+/* ------------------------ Huffman coding ---------------------------- */
+/* -------------- */
+
+#if MAX_ALPHABET <= 0xffff
+# if MAX_ALPHABET <= 1024
+/* positive value takes 15 bits => symbol number occupies <= 10 bits */
+# define huffman_decode_t short
+# else
+# define huffman_decode_t int
+# endif
+#else
+# define huffman_decode_t int
+#endif
+
+#define HUFFMAN_DECODE(ch,table,start_bits) do { \
+ (ch) = table[BIORD (start_bits)]; \
+ if (((int) (ch)) >= 0) \
+ { \
+ BIORD_MORE ((ch) & 31); \
+ (ch) >>= 5; \
+ break; \
+ } \
+ BIORD_MORE (start_bits); \
+ do \
+ { \
+ (ch) = table[BIORD (1) - (ch)]; \
+ BIORD_MORE (1); \
+ } \
+ while (((int) (ch)) < 0); \
+} while (0)
+
+#define HUFFMAN_TABLE_SIZE(n,start_bits) \
+ ((1 << (start_bits)) + ((n) << 1))
+
+static int huffman_decode_create(huffman_decode_t * table, uchar * length,
+ int n, int start_bits)
+{
+ int i, j, k, last, freq[32], sum[32];
+
+ /* calculate number of codewords */
+ memset(freq, 0, sizeof(freq));
+ for (i = 0; i < n; ++i) {
+ if ((k = length[i]) > 31)
+ return RET(COMP_ERR_BROKEN);
+ ++freq[k];
+ }
+
+ /* handle special case(s) -- 0 and 1 symbols in alphabet */
+ if (freq[0] == n) {
+ memset(table, 0, sizeof(table[0]) << start_bits);
+ return (0);
+ }
+ if (freq[0] == n - 1) {
+ if (freq[1] != 1)
+ return RET(COMP_ERR_BROKEN);
+ for (i = 0; length[i] == 0;)
+ ++i;
+ i <<= 5;
+ for (k = 1 << start_bits; --k >= 0;)
+ *table++ = (huffman_decode_t) i;
+ return (0);
+ }
+
+ /* save frequences */
+ memcpy(sum, freq, sizeof(sum));
+
+ /* check code correctness */
+ k = 0;
+ for (i = 32; --i != 0;) {
+ if ((k += freq[i]) & 1)
+ return RET(COMP_ERR_BROKEN);
+ k >>= 1;
+ }
+ if (k != 1)
+ return RET(COMP_ERR_BROKEN);
+
+ /* sort symbols */
+ k = 0;
+ for (i = 1; i < 32; ++i)
+ freq[i] = (k += freq[i]);
+ last = freq[31]; /* preserve number of symbols in alphabet */
+ for (i = n; --i >= 0;) {
+ if ((k = length[i]) != 0)
+ table[--freq[k]] = (huffman_decode_t) i;
+ }
+
+ /* now create decoding table */
+ k = i = (1 << start_bits) + (n << 1);
+ for (n = 32; --n > start_bits;) {
+ j = i;
+ while (k > j)
+ table[--i] = (huffman_decode_t) - (k -= 2);
+ for (k = sum[n]; --k >= 0;)
+ table[--i] = table[--last];
+ k = j;
+ }
+
+ j = i;
+ i = 1 << start_bits;
+ while (k > j)
+ table[--i] = (huffman_decode_t) - (k -= 2);
+
+ for (; n > 0; --n) {
+ for (k = sum[n]; --k >= 0;) {
+ assert(last <= i && last > 0);
+ j = i - (1 << (start_bits - n));
+ n |= table[--last] << 5;
+ do
+ table[--i] = (huffman_decode_t) n;
+ while (i != j);
+ n &= 31;
+ }
+ }
+ assert((i | last) == 0);
+
+ return (0);
+}
+
+/* -------------------- Read/write Huffman code ----------------------- */
+/* ----------------------- */
+
+#define MIN_REPT 2
+
+#if MIN_REPT <= 1
+#error MIN_REPT must exceed 1
+#endif
+
+#define TEMP_TABLE_BITS 8
+
+static int huffman_read_length(bitio_t * bitio, uchar * length, int n)
+{
+ BITIO_LOCALS;
+ huffman_decode_t table[2][HUFFMAN_TABLE_SIZE(64, TEMP_TABLE_BITS)];
+ uchar bits[128];
+ int i, j, k;
+
+ BITIO_ENTER(*bitio);
+ k = BIORD(1);
+ BIORD_MORE(1);
+ if (k != 0) {
+ memset(length, 0, n);
+ goto ret;
+ }
+
+ if (n <= 128) {
+ k = BIORD(5);
+ BIORD_MORE(5);
+ for (i = 0; i < n;) {
+ length[i] = (uchar) BIORD(k);
+ BIORD_MORE(k);
+ if (length[i++] == 0) {
+ j = i + BIORD(4);
+ BIORD_MORE(4);
+ if (j > n)
+ return RET(COMP_ERR_BROKEN);
+ while (i != j)
+ length[i++] = 0;
+ }
+ }
+ goto ret;
+ }
+
+ BITIO_LEAVE(*bitio);
+ i = huffman_read_length(bitio, bits, 128);
+ if (i != 0)
+ return (i);
+ i = huffman_decode_create(table[0], bits, 64, TEMP_TABLE_BITS);
+ if (i != 0)
+ return (i);
+ i = huffman_decode_create(table[1], bits + 64, 64, TEMP_TABLE_BITS);
+ if (i != 0)
+ return (i);
+ BITIO_ENTER(*bitio);
+
+ for (i = 0; i < n;) {
+ HUFFMAN_DECODE(k, table[0], TEMP_TABLE_BITS);
+ if (k <= 31) {
+ length[i++] = (uchar) k;
+ continue;
+ }
+ k &= 31;
+ HUFFMAN_DECODE(j, table[1], TEMP_TABLE_BITS);
+ if (j > 31) {
+ int jj = j - 32;
+
+ j = 1 << jj;
+ if (jj != 0) {
+ if (jj > 16) {
+ j += BIORD(16) << (jj - 16);
+ BIORD_MORE(16);
+ }
+ j += BIORD(jj);
+ BIORD_MORE(jj);
+ }
+ j += 31;
+ }
+ j += MIN_REPT + i;
+ if (j > n)
+ return RET(COMP_ERR_BROKEN);
+ do
+ length[i] = (uchar) k;
+ while (++i != j);
+ }
+
+ret:
+ BITIO_LEAVE(*bitio);
+ return (0);
+}
+
+/* ----------------------- Proper compression ------------------------- */
+/* ------------------ */
+
+#if MIN_BLOCK_BITS > MAX_BLOCK_BITS || MAX_BLOCK_BITS > MAX_BITS_HALF*2
+#error condition MIN_BLOCK_BITS <= MAX_BLOCK_BITS <= MAX_BITS_HALF*2 failed
+#endif
+
+#define DECODE_MAGIC ((int) 0x5abc947fL)
+#define BLOCK_MAGIC ((int) 0x79a3f29dL)
+
+#define START_BITS 13
+
+#define SHORT_INDEX 8u
+
+typedef struct {
+ huffman_decode_t table[HUFFMAN_TABLE_SIZE(ALPHABET_SIZE, START_BITS)];
+ int distance[MAX_DISTANCES];
+ unsigned *crc, *blk_u;
+ unsigned short *blk_s;
+ int block_size_log, /* block_size is integral power of 2 */
+ block_size, /* 1 << block_size_log */
+ last_block_size, /* [original] size of last block */
+ n_blk, /* total number of blocks */
+ comp_block_size, /* size of largest compressed block+32 */
+ check_crc; /* check CRC32? */
+ uchar *comp;
+ int magic;
+} decode_info;
+
+typedef struct {
+ unsigned char *ptr; /* pointer to the first decoded byte */
+ int decoded; /* number of bytes decoded so far */
+ int total; /* total number of bytes in block */
+ int number; /* number of this block */
+} COMP_BLOCK_T;
+
+/* Pointer to compressed data block */
+
+typedef struct {
+ COMP_BLOCK_T b;
+ struct {
+ uchar *first;
+ int size;
+ } orig , comp;
+ struct {
+ uchar *ptr, *src;
+ int rept;
+ } emit;
+ bitio_t bitio;
+ int n;
+ int magic;
+} decode_block;
+
+static int calculate_offset(decode_info * info, unsigned n)
+{
+ unsigned i;
+
+ i = n / (2 * SHORT_INDEX);
+ if (n & SHORT_INDEX)
+ return info->blk_u[i + 1] - info->blk_s[n];
+ else
+ return info->blk_u[i] + info->blk_s[n];
+}
+
+static void do_decode(decode_info * info, decode_block * block, uchar * e)
+{
+ BITIO_LOCALS;
+ uchar *p, *s = 0;
+ int ch;
+
+ if ((p = block->emit.ptr) >= e)
+ return;
+ if (p == block->orig.first) {
+ BIORD_START(block->comp.first);
+ block->emit.rept = 0;
+ } else {
+ BITIO_ENTER(block->bitio);
+ if ((ch = block->emit.rept) != 0) {
+ block->emit.rept = 0;
+ s = block->emit.src;
+ goto copy;
+ }
+ }
+#define OVER if (p < e) goto over; break
+ do {
+ over:
+ HUFFMAN_DECODE(ch, info->table, START_BITS);
+ if ((ch -= 256) < 0) {
+ *p++ = (uchar) ch;
+ OVER;
+ }
+
+ s = p + info->distance[ch >> MAX_LENGTH_BITS];
+
+ ch &= MAX_LENGTH - 1;
+ if (ch <= 3) {
+ p[0] = s[0];
+ p[1] = s[1];
+ p[2] = s[2];
+ p[3] = s[3];
+ p += ch + 1;
+ OVER;
+ } else if (ch >= LONG_LENGTH) {
+ ch -= LONG_LENGTH - LONG_BITS;
+#if (MAX_BLOCK_BITS - 1) + (LONG_LENGTH - LONG_BITS) >= MAX_LENGTH
+ if (ch == DELTA) {
+ ch = BIORD(5);
+ BIORD_MORE(5);
+ ch += DELTA;
+ }
+#endif
+ {
+ int n = 1 << ch;
+
+ if (ch > 16) {
+ n += BIORD(16) << (ch -= 16);
+ BIORD_MORE(16);
+ }
+ n += BIORD(ch);
+ BIORD_MORE(ch);
+ ch = n;
+ }
+ ch += LONG_LENGTH - (1 << LONG_BITS);
+ }
+ ++ch;
+ copy:
+ if (ch > 16) {
+ if (p + ch > e) {
+ block->emit.rept = ch - (int) (e - p);
+ ch = (int) (e - p);
+ goto copy;
+ }
+ do {
+# define X(i) p[i] = s[i]
+ X(0);
+ X(1);
+ X(2);
+ X(3);
+ X(4);
+ X(5);
+ X(6);
+ X(7);
+ X(8);
+ X(9);
+ X(10);
+ X(11);
+ X(12);
+ X(13);
+ X(14);
+ X(15);
+# undef X
+ p += 16;
+ s += 16;
+ }
+ while ((ch -= 16) > 16);
+ }
+ p += ch;
+ s += ch;
+ switch (ch) {
+# define X(i) case i: p[-i] = s[-i]
+ X(16);
+ X(15);
+ X(14);
+ X(13);
+ X(12);
+ X(11);
+ X(10);
+ X(9);
+ X(8);
+ X(7);
+ X(6);
+ X(5);
+ X(4);
+ X(3);
+ X(2);
+# undef X
+ }
+ p[-1] = s[-1];
+ }
+ while (p < e);
+#undef OVER
+ block->emit.ptr = p;
+ block->emit.src = s;
+ BITIO_LEAVE(block->bitio);
+}
+
+/* pretty ugly */
+static int comp_open_file(decode_info ** res, FILE * fd, int check_crc)
+{
+ BITIO_LOCALS;
+ bitio_t Bitio;
+ uchar temp[ALPHABET_SIZE >= HEADER_SIZE ? ALPHABET_SIZE : HEADER_SIZE];
+ uchar *ptr;
+ int header_size, block_size, block_size_log, n_blk, i, n, n_s, n_u;
+ unsigned *blk_u, *blk;
+ unsigned short *blk_s;
+ decode_info *info;
+
+ if (res == 0)
+ return RET(COMP_ERR_PARAM);
+
+ CRC32_init();
+
+ *res = 0;
+
+ if (fread(temp, 1, HEADER_SIZE, fd) != HEADER_SIZE)
+ return RET(COMP_ERR_READ);
+
+ if (memcmp(temp, header_title, 64) != 0)
+ return RET(COMP_ERR_READ);
+
+ ptr = temp;
+#define R4(i) \
+ ((ptr[i] << 24) + (ptr[(i) + 1] << 16) + (ptr[(i) + 2] << 8) + (ptr[(i) + 3]))
+
+ header_size = R4(64);
+ block_size_log = ptr[70];
+ if (block_size_log > MAX_BITS || header_size < 84)
+ return RET(COMP_ERR_BROKEN);
+ block_size = 1 << block_size_log;
+ if (ptr[71] != MAX_DISTANCES)
+ return RET(COMP_ERR_BROKEN);
+ n_blk = R4(72);
+ if (R4(76) !=
+ (ALPHABET_SIZE << 12) + (LONG_BITS << 8) + (LONG_LENGTH << 4) +
+ MAX_LENGTH_BITS)
+ return RET(COMP_ERR_BROKEN);
+
+ if ((ptr = (uchar *) malloc(header_size)) == 0)
+ return RET(COMP_ERR_NOMEM);
+
+ if (fread(ptr + HEADER_SIZE, 1, header_size - HEADER_SIZE, fd) !=
+ (size_t) (header_size - HEADER_SIZE)) {
+ free(ptr);
+ return RET(COMP_ERR_NOMEM);
+ }
+ memcpy(ptr, temp, HEADER_SIZE);
+ header_size -= 4;
+ if (CRC32(ptr, header_size, 0) != (unsigned) R4(header_size)) {
+ free(ptr);
+ return RET(COMP_ERR_BROKEN);
+ }
+ header_size += 4;
+
+ /*
+ blk = (unsigned *) malloc (sizeof (unsigned) * (1 + n_blk));
+ */
+ n = sizeof(unsigned) * (1 + n_blk);
+ if (n < 4 * 1024 * 1024)
+ n = 4 * 1024 * 1024;
+ blk = (unsigned *) malloc(n);
+
+ if (blk == 0) {
+ free(ptr);
+ return RET(COMP_ERR_NOMEM);
+ }
+ n = sizeof(info->crc[0]) * (1 + (check_crc ? (2 * n_blk) : 0));
+ n_u = sizeof(unsigned) * (2 + n_blk / (2 * SHORT_INDEX));
+ n_s = sizeof(unsigned short) * (1 + n_blk);
+ if ((info = (decode_info *) malloc(sizeof(*info) + n + n_u + n_s)) == 0) {
+ free(ptr);
+ free(blk);
+ return RET(COMP_ERR_NOMEM);
+ }
+ cbEGTBCompBytes += sizeof(*info) + n + n_s + n_u;
+ info->crc = (unsigned *) (info + 1);
+ if (check_crc)
+ blk_u = info->blk_u = info->crc + 2 * n_blk;
+ else
+ blk_u = info->blk_u = info->crc;
+ blk_s = info->blk_s =
+ (unsigned short *) (blk_u + 2 + n_blk / (2 * SHORT_INDEX));
+
+ info->check_crc = check_crc;
+ info->block_size_log = block_size_log;
+ info->block_size = block_size;
+ info->n_blk = n_blk;
+
+ if (check_crc) {
+ n_blk <<= 1;
+ i = HEADER_SIZE;
+ for (n = 0; n < n_blk; ++n) {
+ info->crc[n] = R4(i);
+ i += 4;
+ }
+ n_blk >>= 1;
+ }
+
+ i = HEADER_SIZE + (n_blk << 3);
+ BIORD_START(ptr + i);
+
+ info->comp_block_size = 0;
+ for (n = 0; n <= n_blk; ++n) {
+ if ((blk[n] = BIORD(block_size_log)) == 0)
+ blk[n] = block_size;
+ if (info->comp_block_size < (int) (blk[n]))
+ info->comp_block_size = (int) (blk[n]);
+ BIORD_MORE(block_size_log);
+ }
+ info->comp_block_size += 32;
+
+ for (n = 0; n < MAX_DISTANCES; ++n) {
+ info->distance[n] = -((int) BIORD(block_size_log));
+ BIORD_MORE(block_size_log);
+ }
+
+ i += ((n_blk + 1 + MAX_DISTANCES) * block_size_log + 7) >> 3;
+ BIORD_START(ptr + i);
+ BITIO_LEAVE(Bitio);
+ if (huffman_read_length(&Bitio, temp, ALPHABET_SIZE) != 0) {
+ free(blk);
+ free(info);
+ free(ptr);
+ return RET(COMP_ERR_BROKEN);
+ }
+
+ if (huffman_decode_create(info->table, temp, ALPHABET_SIZE, START_BITS) != 0) {
+ free(blk);
+ free(info);
+ free(ptr);
+ return RET(COMP_ERR_BROKEN);
+ }
+
+ info->last_block_size = blk[n_blk];
+ blk[n_blk] = 0;
+ for (n = 0; n <= n_blk; ++n) {
+ i = blk[n];
+ blk[n] = header_size;
+ header_size += i;
+ if (0 == n % (2 * SHORT_INDEX))
+ blk_u[n / (2 * SHORT_INDEX)] = blk[n];
+ }
+ blk_u[n_blk / (2 * SHORT_INDEX) + 1] = blk[n_blk];
+
+ for (n = 0; n <= n_blk; ++n) {
+ i = n / (2 * SHORT_INDEX);
+ if (n & SHORT_INDEX)
+ blk_s[n] = blk_u[i + 1] - blk[n];
+ else
+ blk_s[n] = blk[n] - blk_u[i];
+ }
+
+ free(blk);
+ free(ptr);
+ info->comp = 0;
+ info->magic = DECODE_MAGIC;
+ *res = info;
+
+ return (COMP_ERR_NONE);
+}
+
+static int comp_tell_blocks(decode_info * info)
+{
+ if (info == 0 || info->magic != DECODE_MAGIC)
+ return (-1);
+ return (info->n_blk);
+}
+
+static int comp_init_block(decode_block * block, int block_size, uchar * orig)
+{
+ if (block == 0)
+ return RET(COMP_ERR_PARAM);
+ block->orig.first = orig;
+ block->comp.first = (uchar *) (block + 1);
+ block->b.ptr = 0;
+ block->b.decoded = -1;
+ block->b.total = -1;
+ block->b.number = -1;
+ block->n = -1;
+ block->magic = BLOCK_MAGIC;
+ return (COMP_ERR_NONE);
+}
+
+static int comp_alloc_block(decode_block ** ret_block, int block_size)
+{
+ decode_block *block;
+
+ if (ret_block == 0)
+ return RET(COMP_ERR_PARAM);
+ *ret_block = 0;
+ if ((block = (decode_block *) malloc(sizeof(*block) + block_size)) == 0)
+ return RET(COMP_ERR_NOMEM);
+ cbEGTBCompBytes += sizeof(*block) + block_size;
+ if (0 != comp_init_block(block, block_size, NULL))
+ return RET(COMP_ERR_PARAM);
+ *ret_block = block;
+ return (COMP_ERR_NONE);
+}
+
+#define RETURN(n) \
+ return ((n) == COMP_ERR_NONE ? COMP_ERR_NONE : RET (n));
+
+static int comp_read_block(decode_block * block, decode_info * info, FILE * fd,
+ int n)
+{
+ int comp_size, orig_size, comp_start;
+ uchar *comp, *orig;
+
+ if (block == 0 || block->magic != BLOCK_MAGIC)
+ return RET(COMP_ERR_PARAM);
+ assert(info->magic == DECODE_MAGIC);
+ if ((unsigned) n >= (unsigned) info->n_blk)
+ RETURN(COMP_ERR_PARAM);
+ comp = block->comp.first;
+ block->n = n;
+ orig = block->orig.first;
+ orig_size = info->block_size;
+ if (n == info->n_blk - 1)
+ orig_size = info->last_block_size;
+ block->orig.size = orig_size;
+ comp_start = calculate_offset(info, n);
+ block->comp.size = comp_size = calculate_offset(info, n + 1) - comp_start;
+ if (fseek(fd, comp_start, SEEK_SET) != 0)
+ RETURN(COMP_ERR_READ);
+ if (fread(comp, 1, comp_size, fd) != (size_t) comp_size)
+ RETURN(COMP_ERR_READ);
+ if (info->check_crc
+ && info->crc[(n << 1) + 1] != CRC32(block->comp.first, comp_size, 0))
+ RETURN(COMP_ERR_BROKEN);
+ block->emit.rept = 0;
+ if (comp_size == orig_size) {
+ memcpy(orig, comp, comp_size);
+ block->emit.ptr = orig + comp_size;
+ block->b.decoded = comp_size;
+ } else {
+ block->emit.ptr = orig;
+ block->b.decoded = 0;
+ }
+ block->b.number = n;
+ block->b.ptr = orig;
+ block->b.total = orig_size;
+
+ RETURN(COMP_ERR_NONE);
+}
+
+static int comp_decode_and_check_crc(decode_block * block, decode_info * info,
+ int n, int check_crc)
+{
+ if (block == 0 || block->magic != BLOCK_MAGIC)
+ return RET(COMP_ERR_PARAM);
+ assert(info->magic == DECODE_MAGIC);
+ if ((unsigned) (n - 1) > (unsigned) (block->orig.size - 1))
+ RETURN(COMP_ERR_PARAM);
+ if (check_crc)
+ n = block->orig.size;
+ do_decode(info, block, block->orig.first + n);
+ block->b.ptr = block->orig.first;
+ block->b.total = block->orig.size;
+ if (block->b.decoded >= block->b.total) {
+ if (block->b.decoded > block->b.total)
+ RETURN(COMP_ERR_BROKEN);
+ if (block->emit.rept != 0)
+ RETURN(COMP_ERR_BROKEN);
+ }
+ if (check_crc && info->check_crc
+ && info->crc[block->n << 1] != CRC32(block->orig.first, block->orig.size,
+ 0))
+ RETURN(COMP_ERR_BROKEN);
+
+ RETURN(COMP_ERR_NONE);
+}
+
+#if !defined (COLOR_DECLARED)
+
+/*
+ Test driver
+ */
+
+#define CRC_CHECK 1
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int size;
+ int result;
+ FILE *fp;
+ decode_info *comp_info;
+ decode_block *comp_block;
+ clock_t tStart, tEnd;
+ double dSeconds;
+ uchar rgbBuf[8192 + 32];
+
+ if (2 != argc) {
+ printf("Invalid arguments\n");
+ exit(1);
+ }
+ fp = fopen(argv[1], "rb");
+ if (0 == fp) {
+ printf("Unable to open file\n");
+ exit(1);
+ }
+ result = comp_open_file(&comp_info, fp, CRC_CHECK);
+ if (0 != result) {
+ printf("Unable to read file (1): %d\n", result);
+ exit(1);
+ }
+ if (8192 != comp_info->block_size) {
+ printf("Invalid block size: %d\n", comp_info->block_size);
+ exit(1);
+ }
+ result = comp_alloc_block(&comp_block, comp_info->block_size);
+ if (0 != result) {
+ printf("Unable to allocate block: %d\n", result);
+ exit(1);
+ }
+
+ size = 0;
+ tStart = clock();
+ for (i = 0; i < comp_info->n_blk; i++) {
+ if (0 !=
+ (result = comp_init_block(comp_block, comp_info->block_size, rgbBuf))) {
+ printf("Unable to init block: %d\n", result);
+ exit(1);
+ }
+ if (0 != (result = comp_read_block(comp_block, comp_info, fp, i))) {
+ printf("Unable to read block: %d\n", result);
+ exit(1);
+ }
+ size += comp_block->orig.size;
+ if (0 !=
+ (result =
+ comp_decode_and_check_crc(comp_block, comp_info, comp_block->orig.size,
+ CRC_CHECK))) {
+ printf("Unable to decode block: %d\n", result);
+ exit(1);
+ }
+ }
+ tEnd = clock();
+ dSeconds = (double) (tEnd - tStart) / CLOCKS_PER_SEC;
+ printf("Total memory allocated: %dKb\n", (cbEGTBCompBytes + 1023) / 1024);
+ printf("%g seconds, %dMb, %gMb/sec)\n", dSeconds, size / (1024 * 1024),
+ size / (1024 * 1024) / dSeconds);
+ return 0;
+}
+
+#endif
+#endif