/***********************************************************
    crcio.c -- input/output
***********************************************************/
#ifdef __STDC__
#include <stdlib.h>
#include <stdarg.h>
#endif

#include <errno.h>
#include "slidehuf.h"
#include "intrface.h"

extern int text_mode;
extern int prev_char;
extern int verify_mode;


long reading_size;

#define CRCPOLY  0xA001  /* CRC-16 */
#define UPDATE_CRC(c) mcrc = crctable[(mcrc ^ (c)) & 0xFF] ^ (mcrc >> CHAR_BIT)

FILE *infile, *outfile;
unsigned short mcrc, bitbuf;

static unsigned short crctable[UCHAR_MAX + 1];
static unsigned char  subbitbuf, bitcount;

static int getc_euc_cache;

void make_crctable()
{
    unsigned int i, j, r;

    for (i = 0; i <= UCHAR_MAX; i++) {
        r = i;
        for (j = 0; j < CHAR_BIT; j++)
            if (r & 1) r = (r >> 1) ^ CRCPOLY;
            else       r >>= 1;
        crctable[i] = r;
    }
}


#ifdef NEED_INCREMENTAL_INDICATOR
extern int quiet;
extern int indicator_count;
extern int indicator_threshold;
static void put_indicator( long int count )
{
    if (!quiet)
    {
        while ( count > indicator_count) 
        {
            putchar ('o');
            fflush (stdout);
            indicator_count += indicator_threshold;
        }
    }
}
#endif

unsigned short calccrc( unsigned char *p , unsigned int n )
{
    reading_size += n;
#ifdef NEED_INCREMENTAL_INDICATOR
    put_indicator( reading_size );
#endif
    while (n-- > 0) UPDATE_CRC(*p++);
    return mcrc;
}

void fillbuf(unsigned char n) 
{
    while (n > bitcount) {
        n -= bitcount;
        bitbuf = (bitbuf << bitcount) + (subbitbuf >> (CHAR_BIT - bitcount));
        if (compsize != 0) {
            compsize--;  
            subbitbuf = (unsigned char) getc(infile);
        } 
        else subbitbuf = 0;
        bitcount = CHAR_BIT;
    }
    bitcount -= n;
    bitbuf = (bitbuf << n) + (subbitbuf >> (CHAR_BIT - n));
    subbitbuf <<= n;
}

unsigned short getbits(unsigned char n)
{
    unsigned short x;

    x = bitbuf >> (2 * CHAR_BIT - n);  
    fillbuf(n);
    return x;
}

void putcode( unsigned char n , unsigned short x )  /* Write rightmost n bits of x */
{
    while (n >= bitcount) {
        n -= bitcount;
        subbitbuf += x >> (USHRT_BIT - bitcount);
        x <<= bitcount;
        if (compsize < origsize) {
            if (fwrite(&subbitbuf, 1, 1, outfile) == 0)
                /*    fileerror(WTERR, outfile); */
                exit( errno );
            compsize++;
        } 
        else unpackable = 1;
        subbitbuf = 0;  
        bitcount = CHAR_BIT;
    }
    subbitbuf += x >> (USHRT_BIT - bitcount);
    bitcount -= n;
}

void putbits( unsigned char n , unsigned short x )  /* Write rightmost n bits of x */
{
    x <<= USHRT_BIT - n;
    while (n >= bitcount) {
        n -= bitcount;
        subbitbuf += x >> (USHRT_BIT - bitcount);
        x <<= bitcount;
        if (compsize < origsize) {
            if (fwrite(&subbitbuf, 1, 1, outfile) == 0)
                /* fileerror(WTERR, outfile); */
                exit( errno );
            compsize++;
        } 
        else unpackable = 1;
        subbitbuf = 0;  
        bitcount = CHAR_BIT;
    }
    subbitbuf += x >> (USHRT_BIT - bitcount);
    bitcount -= n;
}

int fread_crc( unsigned char *p, int n, FILE *fp )
{
    if ( text_mode )
        n = fread_txt(p, n, fp);
    else
        n = fread(p, 1, n, fp);
    calccrc(p, n);
    return n;
}

void fwrite_crc( unsigned char *p, int n, FILE *fp )
{
    calccrc(p,n);
    if ( verify_mode ) return;

    if ( fp )
    {
        if ( text_mode )
        {
            if ( fwrite_txt(p , n , fp) )
                fatal_error("File write error\n");
        }
        else
        {
            if (fwrite(p, 1, n, fp) < n)
                fatal_error("File write error\n");
        }
    }
}

void init_code_cache()    /* called from copyfile() in util.c */
{
    getc_euc_cache = EOF;
}

void init_getbits()
{
    bitbuf = 0;  
    subbitbuf = 0;  
    bitcount = 0;
    fillbuf(2 * CHAR_BIT);
}

void init_putbits()
{
    bitcount = CHAR_BIT;  
    subbitbuf = 0;
    getc_euc_cache = EOF;
}


int fwrite_txt( unsigned char *p , int n , FILE *fp )
{
    while ( --n >= 0 )
    {
        if ( *p != '\015' && *p != '\032' )
        {
            putc( *p , fp );
        }

        prev_char = *p++;
    }
    return ( ferror( fp ) );
}


int fread_txt( unsigned char *p , int n , FILE *fp )
{
    int c;
    int cnt = 0;

    while (cnt < n)
    {
        if (getc_euc_cache != EOF)
        {
            c = getc_euc_cache;
            getc_euc_cache = EOF;
        }
        else
        {
            if ((c = fgetc(fp)) == EOF)
                break;

            if (c == '\n') 
            {

                getc_euc_cache = c;
                c = '\r';

            }

        }
        *p++ = c;
        cnt ++;
    }
    return cnt;
}
