#include "smk_hufftree.h"
#include "smk_malloc.h"
struct smk_huff8_t
{
struct smk_huff8_t* b0;
union
{
struct smk_huff8_t* b1;
struct
{
unsigned short value;
unsigned char escapecode;
} leaf;
} u;
};
struct smk_huff16_t
{
struct smk_huff8_t* t;
unsigned short cache[3];
};
#define smk_huff8_build_rec(bs,p) \
{ \
if (!(p = _smk_huff8_build_rec(bs))) \
{ \
fprintf(stderr, "libsmacker::smk_huff8_build_rec(" #bs ", " #p ") - ERROR (file: %s, line: %lu)\n", __FILE__, (unsigned long)__LINE__); \
goto error; \
} \
}
static struct smk_huff8_t* _smk_huff8_build_rec(struct smk_bit_t* bs)
{
struct smk_huff8_t* ret = NULL;
char bit;
smk_bs_read_1(bs, bit);
smk_malloc(ret, sizeof(struct smk_huff8_t));
if (bit)
{
smk_huff8_build_rec(bs, ret->b0);
smk_huff8_build_rec(bs, ret->u.b1);
return ret;
}
smk_bs_read_8(bs, ret->u.leaf.value);
ret->u.leaf.escapecode = 0xFF;
return ret;
error:
smk_huff8_free(ret);
return NULL;
}
short _smk_huff8_lookup(struct smk_bit_t* bs, const struct smk_huff8_t* t)
{
char bit;
smk_assert(bs);
smk_assert(t);
if (!t->b0)
{
return t->u.leaf.value;
}
smk_bs_read_1(bs, bit);
if (bit)
{
return _smk_huff8_lookup(bs, t->u.b1);
}
return _smk_huff8_lookup(bs, t->b0);
error:
return -1;
}
struct smk_huff8_t* _smk_huff8_build(struct smk_bit_t* bs)
{
struct smk_huff8_t* ret = NULL;
char bit;
smk_assert(bs);
smk_bs_read_1(bs, bit);
if (!bit)
{
fputs("libsmacker::_smk_huff8_build(bs) - Warning: initial get_bit returned 0\n", stderr);
goto error;
}
smk_huff8_build_rec(bs, ret);
smk_bs_read_1(bs, bit);
if (bit)
{
fputs("libsmacker::_smk_huff8_build(bs) - ERROR: final get_bit returned 1\n", stderr);
goto error;
}
return ret;
error:
smk_huff8_free(ret);
return NULL;
}
void smk_huff8_free(struct smk_huff8_t* t)
{
smk_assert(t);
if (t->b0)
{
smk_huff8_free(t->b0);
smk_huff8_free(t->u.b1);
}
smk_free(t);
error: ;
}
#define smk_huff16_build_rec(bs,cache,low8,hi8,p) \
{ \
if (!(p = _smk_huff16_build_rec(bs, cache, low8, hi8))) \
{ \
fprintf(stderr, "libsmacker::smk_huff16_build_rec(" #bs ", " #cache ", " #low8 ", " #hi8 ", " #p ") - ERROR (file: %s, line: %lu)\n", __FILE__, (unsigned long)__LINE__); \
goto error; \
} \
}
static struct smk_huff8_t* _smk_huff16_build_rec(struct smk_bit_t* bs, const unsigned short cache[3], const struct smk_huff8_t* low8, const struct smk_huff8_t* hi8)
{
struct smk_huff8_t* ret = NULL;
char bit;
short lowval;
smk_bs_read_1(bs, bit);
smk_malloc(ret, sizeof(struct smk_huff8_t));
if (bit)
{
smk_huff16_build_rec(bs, cache, low8, hi8, ret->b0);
smk_huff16_build_rec(bs, cache, low8, hi8, ret->u.b1);
return ret;
}
smk_huff8_lookup(bs, low8, lowval);
smk_huff8_lookup(bs, hi8, ret->u.leaf.value);
ret->u.leaf.value = lowval | (ret->u.leaf.value << 8);
if (ret->u.leaf.value == cache[0])
{
ret->u.leaf.escapecode = 0;
}
else if (ret->u.leaf.value == cache[1])
{
ret->u.leaf.escapecode = 1;
}
else if (ret->u.leaf.value == cache[2])
{
ret->u.leaf.escapecode = 2;
}
else
{
ret->u.leaf.escapecode = 0xFF;
}
return ret;
error:
smk_huff8_free(ret);
return NULL;
}
struct smk_huff16_t* _smk_huff16_build(struct smk_bit_t* bs)
{
struct smk_huff16_t* big = NULL;
struct smk_huff8_t* low8 = NULL;
struct smk_huff8_t* hi8 = NULL;
short lowval;
char bit;
unsigned char i;
smk_assert(bs);
smk_bs_read_1(bs, bit);
if (!bit)
{
fputs("libsmacker::smk_huff16_build(bs) - ERROR: initial get_bit returned 0\n", stderr);
goto error;
}
smk_huff8_build(bs, low8);
smk_huff8_build(bs, hi8);
smk_malloc(big, sizeof(struct smk_huff16_t));
for (i = 0; i < 3; i ++)
{
smk_bs_read_8(bs, lowval);
smk_bs_read_8(bs, big->cache[i]);
big->cache[i] = lowval | (big->cache[i] << 8);
}
smk_huff16_build_rec(bs, big->cache, low8, hi8, big->t);
smk_huff8_free(hi8);
smk_huff8_free(low8);
smk_bs_read_1(bs, bit);
if (bit)
{
fputs("libsmacker::smk_huff16_build(bs) - ERROR: final get_bit returned 1\n", stderr);
goto error;
}
return big;
error:
smk_huff16_free(big);
smk_huff8_free(hi8);
smk_huff8_free(low8);
return NULL;
}
static int _smk_huff16_lookup_rec(struct smk_bit_t* bs, unsigned short cache[3], const struct smk_huff8_t* t)
{
unsigned short val;
char bit;
if (!t->b0)
{
if (t->u.leaf.escapecode != 0xFF)
{
val = cache[t->u.leaf.escapecode];
}
else
{
val = t->u.leaf.value;
}
if (cache[0] != val)
{
cache[2] = cache[1];
cache[1] = cache[0];
cache[0] = val;
}
return val;
}
smk_bs_read_1(bs, bit);
if (bit)
{
return _smk_huff16_lookup_rec(bs, cache, t->u.b1);
}
return _smk_huff16_lookup_rec(bs, cache, t->b0);
error:
return -1;
}
long _smk_huff16_lookup(struct smk_bit_t* bs, struct smk_huff16_t* big)
{
smk_assert(bs);
smk_assert(big);
return _smk_huff16_lookup_rec(bs, big->cache, big->t);
error:
return -1;
}
void smk_huff16_reset(struct smk_huff16_t* big)
{
smk_assert(big);
big->cache[0] = 0;
big->cache[1] = 0;
big->cache[2] = 0;
error: ;
}
void smk_huff16_free(struct smk_huff16_t* big)
{
smk_assert(big);
if (big->t)
smk_huff8_free(big->t);
smk_free(big);
error: ;
};