From 3fd43cd5fcb22bb65bf2a92a25d95d801b11c9e0 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Wed, 1 Jun 2016 18:58:58 -0700 Subject: Initial checkin for typhoon chess engine. --- src/tbdecode.h | 1038 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1038 insertions(+) create mode 100644 src/tbdecode.h (limited to 'src/tbdecode.h') 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 +#include +#include +#include +#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 -- cgit v1.3