#include "huffman.h"
#include "buffer.h"
#include "Log.h"

#ifdef MAKELOG
#include <stdlib.h>
#endif

/*
 *  Do the huffman-decoding
 */

int* huffman_dualdecoder(bytebuf* hbuff,
	int grBits,
	const struct huffcodetab *h,
	int *is,
	int *to)
{
	register val*	point;
#ifdef MAKELOG
	val*		max;
#endif
	register int	x, y;
	unsigned int	mask;
	int		num;

	if (bs_bitcount(hbuff) <= grBits)
		return is;

	bs_buildmask(hbuff, &mask, &num);

	if (h->linbits)
	{
		while ((is < to) && (bs_bitcount(hbuff)+num > grBits))
		{
			point = h->val;
#ifdef MAKELOG
			max = point + h->treelen;
#endif

			bs_refreshmask(hbuff, &mask, &num);
			/* Lookup in Huffman table */
			while(point[0][0])
			{
				x = mask >> 31;
				num--;
				mask <<= 1;
				if (point[0][x] >= MXOFF)
					point += point[0][x];
				point += point[0][x];
			}

#ifdef MAKELOG
			if (point >= max)
				Log("Tree error %p\n", h);
#endif
			/* end of tree */
			y = point[0][1];
			x = y >> 4;
			y &= 0xf;

			/* Process sign and escape encodings for dual tables */

			if (h->xlen == x)
			{
				bs_refreshmask(hbuff, &mask, &num);
				x += mask >> (32 - h->linbits);
				num -= h->linbits;
				mask <<= h->linbits;
			}
			if (x)
			{
				if (mask & 0x80000000)
					x = -x;
				num--;
				mask <<= 1;
			}

			if (h->ylen == y)
			{
				bs_refreshmask(hbuff, &mask, &num);
				y += mask >> (32 - h->linbits);
				num -= h->linbits;
				mask <<= h->linbits;
			}
			if (y)
			{
				if (mask & 0x80000000)
					y = -y;
				num--;
				mask <<= 1;
			}
#ifdef MAKELOG
			if (abs(x) >= 8192)
				Log("Huffman high value %d\n", x);
			if (abs(y) >= 8192)
				Log("Huffman high value %d\n", x);
#endif
			*is++ = x;
			*is++ = y;
		}
	}
	else
	{
		while ((is < to) && (bs_bitcount(hbuff)+num > grBits))
		{
			point = h->val;
#ifdef MAKELOG
			max = point + h->treelen;
#endif

			bs_refreshmask(hbuff, &mask, &num);
			/* Lookup in Huffman table */
			while(point[0][0])
			{
				x = mask >> 31;
				num--;
				mask <<= 1;
				if (point[0][x] >= MXOFF)
					point += point[0][x];
				point += point[0][x];
			}

#ifdef MAKELOG
			if (point >= max)
				Log("Tree error %p\n", h);
#endif
			/* end of tree */
			y = point[0][1];
			x = y >> 4;
			y &= 0xf;

			/* Process sign and escape encodings for dual tables */

			if (x)
			{
				if (mask & 0x80000000)
					x = -x;
				num--;
				mask <<= 1;
			}
			if (y)
			{
				if (mask & 0x80000000)
					y = -y;
				num--;
				mask <<= 1;
			}

			*is++ = x;
			*is++ = y;
		}
	}

	bs_adjustNbits(hbuff, -num);
	if (bs_bitcount(hbuff) < grBits)
		is -= 2;

	return is;
}

/*
 *  Do the huffman-decoding
 *  Note! for counta,countb -the 4 bit value is returned in y, discard x
 */
int* huffman_quaddecoder(bytebuf* hbuff,
	int grBits,
	const struct huffcodetab *h,
	int *is,
	int *to)
{
	register val*	point;
#ifdef MAKELOG
	val*	max;
#endif
	register int	v, w, x, y;

	if (bs_bitcount(hbuff) <= grBits)
		return is;

	// ensure quad word space
	x = (to - is) & 3;
	to -= x;

	while ((is < to) && (bs_bitcount(hbuff) > grBits))
	{
		point = h->val;
#ifdef MAKELOG
		max = point + h->treelen;
#endif

		/* Lookup in Huffman table */
		do
		{
			point += point[0][bs_get1bit(hbuff)];
		}
		while(point[0][0]);

#ifdef MAKELOG
		if (point >= max)
			Log("Tree error %p\n", h);
#endif
		/* end of tree */
		y = point[0][1];

		v = (y>>3) & 1;
		w = (y>>2) & 1;
		x = (y>>1) & 1;
		y &= 1;

		if (v && bs_get1bit(hbuff))
			v = -v;
		if (w && bs_get1bit(hbuff))
			w = -w;
		if (x && bs_get1bit(hbuff))
			x = -x;
		if (y && bs_get1bit(hbuff))
			y = -y;

		*is++ = v;
		*is++ = w;
		*is++ = x;
		*is++ = y;
	}

	if (bs_bitcount(hbuff) < grBits)
		is -= 4;

	return is;
}
