
#include "rc_decode.h"
#include "basic_op.h"




unsigned rc_dec(ec_dec *curr_dec,unsigned base_val)
{
	unsigned ww;
	curr_dec->ext=curr_dec->rng/base_val;
	ww=(unsigned)(curr_dec->val/curr_dec->ext);
	return base_val-SPEECH_MIN(ww+1,base_val);
}


unsigned int rc_dec_bits(ec_dec *curr_dec,unsigned base_val_b)
{
	ec_window wind;
	int remained;
	unsigned int ret;
	wind=curr_dec->end_window;
	remained=curr_dec->nend_bits;
	if((unsigned)remained<base_val_b)
	{
		do{
			wind|=(ec_window)rc_read_byte_from_end(curr_dec)<<remained;
			remained+=EC_SYM_BITS;
		}while(remained<=EC_WINDOW_SIZE-EC_SYM_BITS);
	}
	ret=(unsigned int)wind&(((unsigned int)1<<base_val_b)-1U);
	wind>>=base_val_b;
	remained-=base_val_b;
	curr_dec->end_window=wind;
	curr_dec->nend_bits=remained;
	curr_dec->nbits_total+=base_val_b;
	return ret;
}


unsigned rc_dec_bin(ec_dec *curr_dec,unsigned base_val_b)
{
	unsigned ww;
	curr_dec->ext=curr_dec->rng>>base_val_b;
	ww=(unsigned)(curr_dec->val/curr_dec->ext);
	return (1U<<base_val_b)-SPEECH_MIN(ww+1U,1U<<base_val_b);
}

void rc_dec_upd(ec_dec *curr_dec,unsigned il,unsigned ih,unsigned it)
{
	unsigned int ww;
	ww=SSC_MUL(curr_dec->ext,it-ih);
	curr_dec->val-=ww;
	curr_dec->rng=il>0?SSC_MUL(curr_dec->ext,ih-il):curr_dec->rng-ww;
	dec_norm(curr_dec);
}


void rc_dec_init(ec_dec *curr_dec,unsigned char *buffer,unsigned int size)
{

	curr_dec->end_offs=0;
	curr_dec->end_window=0;
	curr_dec->nend_bits=0;

	curr_dec->buf=buffer;
	curr_dec->storage=size;

	curr_dec->nbits_total = 9;   

	curr_dec->offs=0;
	curr_dec->rng=1U<<EC_CODE_EXTRA;
	curr_dec->rem=rc_read_byte(curr_dec);
	curr_dec->val=curr_dec->rng-1-(curr_dec->rem>>(EC_SYM_BITS-EC_CODE_EXTRA));
	curr_dec->error=0;
	dec_norm(curr_dec);
}



int rc_dec_bit_logp(ec_dec *curr_dec,unsigned p_log)
{
	unsigned int a, b, c;
	int ret;
	a=curr_dec->rng;
	b=curr_dec->val;
	c=a>>p_log;
	ret=b<c;
	if(!ret)curr_dec->val=b-c;
	curr_dec->rng=ret?c:a-c;
	dec_norm(curr_dec);
	return ret;
}

int rc_dec_icdf(ec_dec *curr_dec,const unsigned char *cdf,unsigned fb)
{

	unsigned int a, b, c, d;
	int ret;
	c=curr_dec->rng;
	b=curr_dec->val;
	a= c>>fb;


	ret=-1;
	do{
		d=c;
		c=SSC_MUL(a,cdf[++ret]);
	}while(b<c);
	curr_dec->val=b-c;
	curr_dec->rng=d-c;
	dec_norm(curr_dec);
	return ret;
}

unsigned int rc_dec_uint(ec_dec *curr_dec,unsigned int base_val)
{
	unsigned ft, s;
	int ftb;

	base_val--;
#ifndef HW_FOR_GCC
	ftb=EC_ILOG(base_val);
#else
	asm volatile
	(
		"clz      %0,%1 \n\t"
		"RSB		%0,%0,#0x20 \n\t"
		:"=a"(ftb)
		:"a"(base_val) 
	);
#endif
	if(ftb>EC_UINT_BITS)
	{
		unsigned int t;
		ftb-=EC_UINT_BITS;
		ft=(unsigned)(base_val>>ftb)+1;
		s=rc_dec(curr_dec,ft);
		rc_dec_upd(curr_dec,s,s+1,ft);
		t=(unsigned int)s<<ftb|rc_dec_bits(curr_dec,ftb);
		if(t<=base_val) return t;
		curr_dec->error=1;
		return base_val;
	}else{
		base_val++;
		s=rc_dec(curr_dec,(unsigned)base_val);
		rc_dec_upd(curr_dec,s,s+1,(unsigned)base_val);
		return s;
	}
}


