/*****************************************************************************
 *                                                                           *
"This software module was originally developed by 

Martin Dietz (Fraunhofer Gesellschaft IIS)

and edited by

Ralph Sperschneider (Fraunhofer Gesellschaft IIS)

in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, 
14496-1,2 and 3. This software module is an implementation of a part of one or more 
MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 
Audio standard. ISO/IEC  gives users of the MPEG-2 NBC/MPEG-4 Audio 
standards free license to this software module or modifications thereof for use in 
hardware or software products claiming conformance to the MPEG-2 NBC/MPEG-4
Audio  standards. Those intending to use this software module in hardware or 
software products are advised that this use may infringe existing patents. 
The original developer of this software module and his/her company, the subsequent 
editors and their companies, and ISO/IEC have no liability for use of this software 
module or modifications thereof in an implementation. Copyright is not released for 
non MPEG-2 NBC/MPEG-4 Audio conforming products.The original developer
retains full right to use the code for his/her  own purpose, assign or donate the 
code to a third party and to inhibit third party from using the code for non 
MPEG-2 NBC/MPEG-4 Audio conforming products. This copyright notice must
be included in all copies or derivative works." 
Copyright(c)1998.
 *                                                                           *
 ****************************************************************************/
#ifdef VERSION2
#include <stdio.h>
#include <stdlib.h>
#include "bitfct.h"
#include "reorderspec.h"
/****************************************************************************
 ***    
 ***    TransferBitsBetweenBitBuf()
 ***    
 ***    transfers 'NoOfBits' bits from the bitstream-buffer 'in' in the
 ***    bitstream-buffer 'out', MSB first
 ***    
 ***    R. Sperschneider     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

void TransferBitsBetweenBitBuf ( BIT_BUF *in, BIT_BUF *out, unsigned long noOfBits )
{
  while ( noOfBits )
    {
      unsigned long transferBits;
      unsigned long tempCodeword;
      transferBits = min ( noOfBits, UINT_BITLENGTH );
      tempCodeword = ReadBitBuf ( in, transferBits );
      WriteBitBuf ( out, tempCodeword, transferBits );
      noOfBits -= transferBits;
    }
}

/****************************************************************************
 ***    
 ***    WriteBitBuf()
 ***    
 ***    writes 'no_of_bits' bits from the variable 'value' in the
 ***    bitstream-buffer 'data', MSB first
 ***    
 ***    M.Dietz     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

void WriteBitBuf( BIT_BUF *data, unsigned long value, unsigned long no_of_bits )

{

    unsigned long mask;             /* bit mask                         */

    if( no_of_bits == 0 ) 
      return;

    mask = 0x1;
    mask <<= no_of_bits - 1;

    data->bit_count += no_of_bits;

    while( no_of_bits > 0 )
      {
        while( no_of_bits > 0 && data->valid_bits < 8 ) 
	  {
            data->byte <<= 1;
            if( value & mask ) data->byte |= 0x1;
            value <<= 1;
            no_of_bits--;
            data->valid_bits++;
	  }
        if( data->valid_bits == 8 ) 
	  {
            *data->byte_ptr++ = data->byte;
            data->byte = 0;
            data->valid_bits = 0;
          }
      }
}



/****************************************************************************
 ***    
 ***    InitWriteBitBuf()
 ***    
 ***    inititalizes a bitstream buffer
 ***    
 ***    M.Dietz     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

void InitWriteBitBuf( BIT_BUF *bit_buf, unsigned char *buffer )
{
    bit_buf->byte_ptr = buffer;
    bit_buf->byte = 0;
    bit_buf->valid_bits = 0;
    bit_buf->bit_count = 0;
}


/****************************************************************************
 ***    
 ***    FlushWriteBitBuf()
 ***    
 ***    flushes the last, possibly not stored byte of a bitstream written
 ***    with writeBitBuf
 ***    
 ***    M.Dietz     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

unsigned long FlushWriteBitBuf( BIT_BUF *bit_buf )
{
    unsigned long flushbits;
    flushbits = 8 - bit_buf->bit_count % 8;
    if( flushbits < 8 )
      WriteBitBuf( bit_buf, 0x0, flushbits );
    return bit_buf->bit_count;
}

/****************************************************************************
 ***    
 ***    GetBitCount()
 ***    
 ***    returns the number of bits written/read
 ***    
 ***    M.Dietz     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

unsigned long GetBitCount( BIT_BUF *bit_buf )
{
    return bit_buf->bit_count;
}



/****************************************************************************
 ***
 ***    InitReadBitBuf()
 ***
 ***    inititalizes a bitstream buffer for reading
 ***
 ***    M.Dietz     FhG IIS/INEL
 ***
 ****************************************************************************/

void InitReadBitBuf( BIT_BUF *bit_buf, unsigned char *buffer )
{
    bit_buf->byte_ptr   =  buffer;
    bit_buf->byte       = *buffer;
    bit_buf->valid_bits = 8;
    bit_buf->bit_count  = 0;
}



/****************************************************************************
 ***
 ***    ReadBitBuf()
 ***
 ***    reads 'no_of_bits' bits from the bitstream buffer 'data'
 ***    in the variable 'value'
 ***
 ***    M.Dietz     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

unsigned long ReadBitBuf ( BIT_BUF*        data,       /* bitstream-buffer                     */
                           unsigned long   no_of_bits) /* number of bits to read               */
{
    unsigned long mask;             /* bit mask */
    unsigned long value;

    mask  = 0x80;
    value = 0;
    if ( no_of_bits == 0 ) 
      return ( value );

    data->bit_count += no_of_bits;

    while ( no_of_bits > 0 )
      {
        while ( no_of_bits > 0 && data->valid_bits > 0 ) 
	  {
	    value <<= 1;
            if ( data->byte & mask ) 
              value |= 0x1;
            data->byte <<= 1;
            no_of_bits--;
            data->valid_bits--;
	  }
        if ( data->valid_bits == 0 ) 
	  {
            data->byte_ptr ++;
            data->byte = *data->byte_ptr;
            data->valid_bits = 8;
	  }
    }
    return ( value );
}

/****************************************************************************
 ***
 ***    CopyBitBufPointer()
 ***
 ***    copies the Pointer of a bitstream buffer
 ***    
 ***
 ***    M.Dietz/A.Ehret     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

void CopyBitBufPointer ( BIT_BUF *ptrDest, BIT_BUF *ptrSrc  )
{
  ptrDest->byte_ptr   = ptrSrc->byte_ptr;
  ptrDest->byte       = ptrSrc->byte;
  ptrDest->valid_bits = ptrSrc->valid_bits;
  ptrDest->bit_count  = ptrSrc->bit_count;
}

/****************************************************************************
 ***
 ***    PrintBitBufPointer()
 ***
 ***    prints pointer information of a bitstream buffer
 ***    
 ***
 ***    R. Sperschneider     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/

void PrintBitBufPointer ( BIT_BUF *ptr )
{
  fprintf ( stderr,
            "byte_ptr: %p, byte: %3hu, valid_bits: %hu, bit_count: %4hu\n",
            ptr->byte_ptr, 
            ptr->byte,
            ptr->valid_bits, 
            ptr->bit_count );
}



unsigned short mask    = 0x8000;
unsigned short polynom = 0x8005; 

unsigned short CalcCRC16 ( BIT_BUF* bitbuf, unsigned short crc_reg, short bit_num )
{
    unsigned short flag;
    short i;

    for ( i = 0; i < bit_num; i++ ) 
      {
        if ( crc_reg & mask ) 
          flag = 1;
        else 
          flag = 0;
        flag ^= ReadBitBuf( bitbuf, 1 );
        crc_reg <<= 1;
        if ( flag ) 
          crc_reg ^= polynom;
      }
    return( crc_reg );
}

/****************************************************************************
 ***
 ***    SplitCodeword()
 ***
 ***    splits 'split' bits of the codeword of lenght 'length' in *io,
 ***    returns the rest of the codeword, the splitted of codeword then
 ***    is in *io
 ***
 ***    A.Ehret     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/
int SplitCodeword(int *io, short split, short length) {
  
  int bitTempOrig;
  
  bitTempOrig = *io;

  /* shift #(length-split), io now contains first #split bits */
  *io = bitTempOrig>>(length-split);
  
  return ( ( ( 1<<(length-split) )-1 ) & bitTempOrig );
}



/* #define TEST */

#ifdef TEST
#include <stdio.h>

void main( void )
{
  static unsigned char buf[100];
  BIT_BUF bb,bb2;
  int cnt;

  InitWriteBitBuf( &bb, buf );
  WriteBitBuf( &bb, 0xa, 4 );
  WriteBitBuf( &bb, 0xb, 4 );
  WriteBitBuf( &bb, 0xc, 4 ); 
  cnt = GetBitCount( &bb );
  cnt = FlushWriteBitBuf( &bb ); 
  fprintf(stderr,"\nLen %3d  %x %x %x %x\n",cnt,buf[0], buf[1], buf[2], buf[3]);
  InitReadBitBuf( &bb2, buf );
  fprintf(stderr,"  %x  %x  %x  %x\n",
          ReadBitBuf( &bb2, 4 ), 
          ReadBitBuf( &bb2, 4 ), 
          ReadBitBuf( &bb2, 4 ), 
          ReadBitBuf( &bb2, 4 ) );
}
#endif


#if 0
/****************************************************************************
 ***
 ***    BitRoutines
 ***
 ***    
 ***    
 ***    
 ***
 ***    A.Ehret     FhG IIS/INEL                                          
 ***                                                                      
 ****************************************************************************/
static char BitVector[MAX_SPEC_BITLENGTH];
static char *true  ="1";
static char *false ="0";
static char *init  ="-";

void WriteCodeWord (int pos, int code, int len) {
  int i;

  for (i=0; i<len; i++)
    if ( code & (1<<i) ) memcpy (BitVector+pos+len-1-i, true, 1);
    else                 memcpy (BitVector+pos+len-1-i, false, 1);
}


void PrintBitVector (int nr) {
  int i;
  unsigned short  segmentWidth = 20; /* for efficient use of this function,the segmentWidth shold be delivered
					via function parameter */
  char out[segmentWidth+1];
  
  for (i=0;i<nr;i++) {
    memcpy (out,BitVector+i*segmentWidth, segmentWidth);
    fprintf(stderr,"\nSegment #%d  %.50s",i,out);
  }

  fprintf(stderr,"\n");
}

void InitBitVector (void) {
  int i;

  for (i=0; i<MAX_SPEC_BITLENGTH-1; i++)
    memcpy (BitVector+i, init, 1);
}

void WriteBitVector (char *out, int len) {
  int i,j;
  int Word;
  char bit[2];
  int WordLength=8; /* fwrite is using bytes as data-objects */

  len = ( (int) (len/WordLength) + 1 ); 

  for (i=0;i<len;i++) {
    Word = 0;
    for (j=0;j<WordLength;j++) {
      memcpy (bit, BitVector+i*WordLength+7-j, 1);
      Word += (1<<j) * atoi (bit);
    }
    out[i]=Word;
#ifdef DEBUG_TESTVEC
    fprintf(stderr,"\nout[%d]=%d",i,out[i]);
#endif
  }

}
#endif
#endif /*VERSION2*/
