/*
 *	THIS ROUTINE IS PART OF THE CLEMENTINE PDS FILE READER PROGRAM.
 *	IT WAS WRITTEN BY ACT CORP. IN DIRECT SUPPORT TO THE 
 *	CLEMENTINE (DSPSE) PROGRAM.
 *
 *	IF YOU FIND A PROBLEM OR MAKE ANY CHANGES TO THIS CODE PLEASE CONTACT
 *	Dr. Erick Malaret at ACT Corp. 
 *			tel: (703) 742-0294
 *			     (703) 683-7431
 *                       email:	nrlvax.nrl.navy.mil
 *	
 *
 */
#include 
#include "jpeg_c.h"

void cBitStream( BitStream *bs, char *fn, Fmode fm )
{
	cByteStream( &bs->bytestream, fn, fm );
	bs->BitBuffer = 0;
	bs->bytesout = 0;
	bs->outstring = NULL;
	bs->BitBuffMask =  (fm==OUTPUT) ? 0x80:0x00;
	bs->bitmask[0] = 0x0000; bs->bitmask[1] = 0x0001; bs->bitmask[2] = 0x0002;
	bs->bitmask[3] = 0x0004; bs->bitmask[4] = 0x0008; bs->bitmask[5] = 0x0010;
	bs->bitmask[6] = 0x0020; bs->bitmask[7] = 0x0040; bs->bitmask[8] = 0x0080;
	bs->bitmask[9] = 0x0100; bs->bitmask[10] = 0x0200; bs->bitmask[11] = 0x0400;
	bs->bitmask[12] = 0x0800; bs->bitmask[13] = 0x1000; bs->bitmask[14] = 0x2000;
	bs->bitmask[15] = 0x4000; bs->bitmask[16] = 0x8000;
}

void dBitStream(BitStream *bs)
{
	if ( bs->bytestream.mode == OUTPUT ) {
		if ( bs->BitBuffMask != 0x80 ) {
			while (bs->BitBuffMask) {
				bs->BitBuffer |= bs->BitBuffMask;
				bs->BitBuffMask >>= 1;
			}
			if ( bs->mode )
				bs->outstring[bs->bytesout] = bs->BitBuffer;
			else
				ByteStream_write( &bs->bytestream, bs->BitBuffer );
			bs->bytesout++;
		}
		if ( bs->mode ) {
			if ( fwrite(bs->outstring,sizeof(char),bs->bytesout,bs->bytestream.file) == 0 )
				printf("Error: writing output bitstream to file.\n");
		}
		if ( fseek(bs->bytestream.file,8,0) )
			printf("Error: fseek in subroutine dBitStream().\n");
		else {
			if ( fwrite(&(bs->bytesout),sizeof(long),1,bs->bytestream.file) == 0 )
				printf("Error: writing bytesout value to file.\n");
		}
	}
	dByteStream(&bs->bytestream);
}

short BitStream_write(BitStream *bs, short bits, short width)
{
	unsigned short BitMask = bs->bitmask[width];

	while ( BitMask ) {
		if ( bits & BitMask ) bs->BitBuffer |= (short)bs->BitBuffMask;
		BitMask >>= 1;
		bs->BitBuffMask >>= 1;
		if ( !bs->BitBuffMask ) {
			if ( bs->mode )
				bs->outstring[bs->bytesout] = bs->BitBuffer;
			else
				ByteStream_write( &bs->bytestream, bs->BitBuffer );
			bs->bytesout++;
			bs->BitBuffer = 0;
			bs->BitBuffMask = 0x80;
		}
	}
	return bs->bytestream.stat;
}

short BitStream_read( BitStream *bs, short w )
{
	unsigned short RetVal = 0, BitMask = bs->bitmask[w];

	while ( BitMask ) {
		if ( !bs->BitBuffMask ) {
			if ( bs->mode ) {
				bs->BitBuffer = ((short)bs->outstring[bs->bytesout]) & 0x00ff;
			} else
				bs->BitBuffer = ByteStream_read(&bs->bytestream);

			bs->bytesout++;
			bs->BitBuffMask = 0x80;
		}
		if ( bs->BitBuffer & bs->BitBuffMask ) RetVal |= BitMask;
		bs->BitBuffMask >>= 1;
		BitMask >>= 1;
	}
	return RetVal;
}

void cByteStream(ByteStream *Bs, char *FileName, Fmode FileMode)
{
	Bs->mode = FileMode;
	if ( FileName != NULL ) {
		Bs->file = fopen(FileName,(Bs->mode==INPUT) ? "rb":"wb");
		if ( Bs->file == NULL ) printf("ByteStream constructor error.\n");
		Bs->stat = 0;
	}
}

void dByteStream(ByteStream *Bs)
{
	if ( Bs->file ) {
		fclose(Bs->file);
		Bs->file = NULL;
	}
}

short ByteStream_read(ByteStream *Bs)
{
	short     c, d;
	char	cval;
        int	n;

	if ( Bs->mode == INPUT ) {
		/* c = fgetc( Bs->file ); */
		n=fread(&cval,sizeof(char),1,Bs->file);
                c	= cval; 
		if ( n != 1 ) Bs->stat = EOF;
		return c;
	} else
		Bs->stat = EOF;
}

short ByteStream_write(ByteStream *Bs, short c)
{
	if ( (Bs->mode != OUTPUT) || (fputc(c,Bs->file) == EOF) ) Bs->stat = EOF;
	return Bs->stat;
}

short ByteStream_status(ByteStream *Bs)
{
	return Bs->stat;
}