/* YUNTAI KYONG
Advanced Internet Service
term project
*/

#include <assert.h>		// assert()
#include <stdio.h>		// FILE
#include <stdlib.h>		// exit()
#include <memory.h>		// memcpy()
#include "fileStream.h"
extern void error(char*);
////////////////////////////////////////////////////////////
//		Constructor
//		@param
//			inputFile: set file stream
fileStream::fileStream(FILE *inputFile)
{
	assert( inputFile != NULL );
	this->inputFile = inputFile;
	m_b_Mark = 0;
	bytesToRead = 0;
	m_cur_pos   = 0;
	m_cur_file_pos = 0;
	get_next_data();
}

int 
fileStream::getSizeFromMark()
{
	return (m_cur_file_pos-m_mark_pos);
}

void
fileStream::mark()
{	
	assert(BYTEALIGNED());
	assert(m_b_Mark == 0);
	m_mark_pos = m_cur_file_pos;
	m_b_Mark = 1;
}



int
fileStream::load(unsigned  char *outBuf)
{	
	static __int64 totalLoadedBytes = 0;
	assert(BYTEALIGNED());
	assert(m_b_Mark == 1);
	fpos_t current_pos;
	
	int size = m_cur_file_pos - m_mark_pos;
	
	fgetpos( inputFile, &current_pos);
	
	fseek( inputFile, SEEK_SET , m_mark_pos );
	fread( outBuf, 1, size, inputFile );
	
	fsetpos( inputFile,  &current_pos );
	
	fpos_t current_pos2;
	fgetpos( inputFile, &current_pos2 );
	assert( current_pos==current_pos2 );

	/*
	printf("mark: %d\n", m_mark_pos );
	printf("cur: %d\n", m_cur_file_pos );
	printf("load: %d bytes\n",  size );
	*/
	totalLoadedBytes+= size;
	printf("total: %d bytes\n", totalLoadedBytes );
	m_b_Mark = 0;
	return size;
}

void
fileStream::rewind()
{	
	assert(BYTEALIGNED());
	assert(m_b_Mark == 1);
	printf("rewind!!!!");
	cur_byte	= m_mark;
	m_cur_pos	= m_mark_pos;
	m_b_Mark = 0;
}


////////////////////////////////////////////////////////////
//		get_next_data
//		@description
//			read data from file and fill it into the
//ternal buffer


int
fileStream::get_next_data(void)
{
	
	if(!bytesToRead) 
	{	
		bytesToRead = fread(buffer, 1, BUFFER_SIZE, inputFile);
		if( bytesToRead == 0 )
			return -2;
		m_cur_pos = 0;
		cur_byte = buffer;
		cur_bit = 7;
	}
	return 1;
}
////////////////////////////////////////////////////////////
//		get_bits
//		@param
//			bits_left: number of bits to be read
//		@return
//			Value
// return next bits 


unsigned int
fileStream::get_bits(int bits_left)
{
	unsigned int byte, result;
	
	result = 0;
	do {
		if(BYTEALIGNED() && (bits_left >= 8))
        {
			bits_left -= 8;
			result |= get_byte() << bits_left;
        }
		else
        {
			byte = *cur_byte;
			byte &= (unsigned int) 0xffffffff >> (31 - cur_bit);
			if(cur_bit >= bits_left)
            {
				result |= byte >> (cur_bit - bits_left + 1);
				cur_bit -= bits_left;
				bits_left = 0;
            }
			else
            {
				result |= byte << (bits_left - cur_bit - 1);
				bits_left -= cur_bit + 1;
				cur_bit = 7;
				cur_byte++;
				m_cur_file_pos++;
				m_cur_pos++;
				bytesToRead--;
				get_next_data();
            }
        }
    } while(bits_left);
	return result;
}


////////////////////////////////////////////////////////////
//		get_byte
//		@return
//			value read
/* get next byte */



unsigned int 
fileStream::get_byte()
{
	unsigned int byte;
	if( get_next_data() == -2 )
		return -2;
	
	if(cur_bit != 7)
		error("get_byte(): Non byte aligned in get_byte.  MPEG file is corrupted");
	m_cur_file_pos++;
	m_cur_pos++;
	byte = *cur_byte++;
	bytesToRead--;
	return byte;
}

/* check next bits are equal to given bit string */
unsigned int 
fileStream::next_bits(int bit_count, unsigned int string)
{
	unsigned char *ptr;

	if(cur_bit != 7)
	{
		int j =0;
		int i = 3/j;

		error("Comparing non byte aligned data.  MPEG file is corrupted");
	}
	/* Check that we have enough data in buffer to do non destructive read */
	int bytes = bit_count >> 3;
	
	if(bytes > bytesToRead)
    {	
		assert( bytes > bytesToRead );
		printf( "bytes: %d, bytesToRead: %d\n", bytes, bytesToRead );
		int ret;
		memcpy( buffer, cur_byte, bytesToRead);
		ret = fread(buffer+bytesToRead, 1, BUFFER_SIZE-bytesToRead,inputFile);
		if( ret == 0 )
		{
			printf("end of file!\n");
			return -2;
		}
		bytesToRead += ret;
		printf("ret: %d, bytesToRead: %d\n", ret, bytesToRead );
		cur_byte = buffer;
		m_cur_pos = 0;
	}
	
	ptr = cur_byte;
	do 
	{
		if(*ptr++ != ((string >> (bit_count -= 8)) & 255))
			return 0;
		
	} while(bit_count);
	return 1;
}



/* return next bit */
unsigned int 
fileStream::get_bit()
{
	unsigned int bit;
	
	get_next_data();
	bit = (*cur_byte >> cur_bit) & 1;
	
	if(cur_bit == 0)
    {
		m_cur_file_pos++;
		m_cur_pos++;
		cur_byte++;
		bytesToRead--;
		cur_bit = 7;
    }
	else
		cur_bit--;
	
	return bit;
}

