#include <stdio.h>
#include <stdlib.h>
#include "bitstream.h"

/* K O N S T A N T E N */
const unsigned int   mask [33] = {
    0x00000000, 0x00000001, 0x00000003, 0x00000007,
    0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,
    0x000000FF, 0x000001FF, 0x000003FF, 0x000007FF,
    0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,
    0x0000FFFF, 0x0001FFFF, 0x0003FFFF, 0x0007FFFF,
    0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,
    0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
    0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,
    0xFFFFFFFF,
};

/* V A R I A B L E N */
unsigned int          Speicher [MEMSIZE];       // enthaelt den Lese-Puffer
unsigned int          dword     = 0;            // 32Bit-Wort fuer Bitstrom-I/O
unsigned int          pos       = 0;            // Position im aktuell decodierten 32Bit-Wort
unsigned int          Zaehler   = 0;            // aktuelle Position im Lese-Puffer
static unsigned int   WordsRead = 0;            // Zaehler fuer Anzahl decodierter 32Bit-Worte


size_t
ReadLE32 ( FILE* fp, unsigned int* buff, size_t words )
{
    words = fread ( buff, 4, words, fp );

#ifdef BIG_ENDIAN_MACHINE
#pragma message ""
#pragma message "Compiled for Use with Big Endian machines"
#pragma message ""
    {
        unsigned char* p = (unsigned char*) buff;
        unsigned char  c;
        size_t         i;

        for ( i = 0; i < words; i++, p += 4 ) {
            c = p[0]; p[0] = p[3]; p[3] = c;
            c = p[1]; p[1] = p[2]; p[2] = c;
        }
    }
#endif

    return words;
}

/* F U N K T I O N E N */
// resets bitstream decoding
void
Reset_BitstreamDecode ( void )
{
    dword     = 0;
    pos       = 0;
    Zaehler   = 0;
    WordsRead = 0;
}


// reports the number of read bits
unsigned int
BitsRead ( void )
{
    return 32 * WordsRead + pos;
}


// read desired number of bits out of the bitstream
unsigned int
Bitstream_read ( const unsigned int bits )
{
    unsigned int out = dword;

    pos += bits;

    if ( pos < 32 ) {
        out >>= (32-pos);
    }
    else {
        dword = Speicher [ Zaehler = (Zaehler+1) & MEMMASK ];
        pos  -= 32;
        if ( pos ) {
            out <<= pos;
            out  |= dword >> (32-pos);
        }
        WordsRead++;
    }

    return out & mask [bits];
}


// read desired number of bits out of the bitstream
unsigned int
Bitstream_read1 ( void )
{
    unsigned int out = dword;

    if ( ++pos < 32 ) {
        out >>= (32-pos);
    }
    else {
        dword = Speicher [ Zaehler = (Zaehler+1) & MEMMASK ];
        pos   = 0;
        WordsRead++;
    }

    return out & 1;
}


// decode huffman
int
Huffman_Decode ( const HuffmanTyp* Table )
{
    // load preview and decode
    unsigned int code  = dword << pos;
    if (pos>18)  code |= Speicher[(Zaehler+1)&MEMMASK] >> (32-pos);

    while ( code < Table -> Code )
        Table++;

    if ( ( pos += Table->Length ) >= 32 ) {
        pos -= 32;
        dword = Speicher [ Zaehler = (Zaehler+1) & MEMMASK ];
        WordsRead++;
    }

    return Table -> Value;
}


// faster huffman through previewing less bits
int
Huffman_Decode_fast ( const HuffmanTyp* Table )
{
    unsigned int code  = dword << pos;
    if (pos>22)  code |= Speicher[(Zaehler+1)&MEMMASK] >> (32-pos);

    while ( code < Table->Code )
        Table++;

    if ( ( pos += Table -> Length ) >= 32 ) {
        pos -= 32;
        dword = Speicher [ Zaehler = (Zaehler+1) & MEMMASK ];
        WordsRead++;
    }

    return Table -> Value;
}


// even faster huffman through previewing even less bits
int
Huffman_Decode_faster ( const HuffmanTyp* Table )
{
    // load preview and decode
    unsigned int code  = dword << pos;
    if (pos>27)  code |= Speicher[(Zaehler+1)&MEMMASK] >> (32-pos);

    while ( code < Table -> Code )
        Table++;

    if ( ( pos += Table->Length ) >= 32 ) {
        pos -= 32;
        dword = Speicher [ Zaehler = (Zaehler+1) & MEMMASK ];
        WordsRead++;
    }

    return Table -> Value;
}


static int
cmpfn ( const void* p1, const void* p2 )
{
    if ( ((const HuffmanTyp*) p1)->Code < ((const HuffmanTyp*) p2)->Code ) return +1;
    if ( ((const HuffmanTyp*) p1)->Code > ((const HuffmanTyp*) p2)->Code ) return -1;
    return 0;
}


// sort huffman-tables by codeword
// offset resulting value
void
Resort_HuffTables ( const unsigned int elements, HuffmanTyp* Table, const int offset )
{
    unsigned int  i;

    for ( i = 0; i < elements; i++ ) {
        Table[i].Code <<= 32 - Table[i].Length;
        Table[i].Value  =  i - offset;
    }
    qsort ( Table, elements, sizeof(*Table), cmpfn );
}
