/**
 * \file      ZipSubStream.cpp
 * \version   $Id$
 * \author    $$$03公司
 *            $$$03公司@###.com
 * \date      2006-7-19  21:11:00
 * \brief     ZIP包中子文件流
 * 
 *	      ZIP包中子文件流
 */

// ZipSubStream.cpp: implementation of the ZipSubRStream class.
//
//////////////////////////////////////////////////////////////////////
#include "../include/engine.h"
#include "../include/ZipSubStream.h"
#include "../include/Stream.h"
#include "../../Zlib/Zlib.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

const DWORD ZipSubRStream::csm_streamCaps      = DWORD(Stream::StreamRead) | DWORD(Stream::StreamPosition);
const DWORD ZipSubRStream::csm_inputBufferSize = 4096;

const DWORD ZipSubWStream::csm_streamCaps      = DWORD(Stream::StreamWrite);
const DWORD ZipSubWStream::csm_bufferSize      = (2048 * 1024);

//--------------------------------------------------------------------------
//--------------------------------------
//
/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
ZipSubRStream::ZipSubRStream(bool bFullBuffer)
: m_pStream(NULL),
m_bFullBuffer(bFullBuffer),
m_uncompressedSize(0),
m_currentPosition(0),
m_pInputBuffer(NULL),
m_pOutputBuffer(NULL),
m_pZipStream(NULL),
m_originalSlavePosition(0),
m_curSlavePosition(0)
{
	//
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
ZipSubRStream::~ZipSubRStream()
{
	detachStream();
	delete [] m_pInputBuffer;
	delete [] m_pOutputBuffer;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param io_pSlaveStream : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubRStream::attachStream(Stream* io_pSlaveStream)
{
	AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
	AssertFatal(m_pStream == NULL,       "Already attached!");

	m_pStream          = io_pSlaveStream;
	m_originalSlavePosition = io_pSlaveStream->getPosition();
	m_curSlavePosition	=	m_originalSlavePosition;
	//m_uncompressedSize = 0;
	m_currentPosition  = 0;

	// Initialize zipStream state...
	m_pZipStream   = new z_stream_s;

	m_pZipStream->zalloc = Z_NULL;
	m_pZipStream->zfree  = Z_NULL;
	m_pZipStream->opaque = Z_NULL;

	if(m_bFullBuffer)
	{
		if(m_pInputBuffer)
			delete [] m_pInputBuffer;

		if(m_pOutputBuffer)
		{
			delete [] m_pOutputBuffer;
			m_pOutputBuffer = NULL;
		}

		BYTE inBuffer[csm_inputBufferSize];
		m_pInputBuffer = inBuffer;
		
		DWORD buffSize = fillBuffer(csm_inputBufferSize);

		m_pZipStream->next_in  = m_pInputBuffer;
		m_pZipStream->avail_in = buffSize;
		m_pZipStream->total_in = 0;
		inflateInit2(m_pZipStream, -MAX_WBITS);

		setStatus(Ok);

		BYTE* pOutputBuffer = new BYTE[m_uncompressedSize];
		bool b = read(pOutputBuffer,m_uncompressedSize);
		m_pOutputBuffer = pOutputBuffer;
		setPosition(0);
		m_pInputBuffer = NULL;
		return b;
	}else{
		if(!m_pInputBuffer)
			m_pInputBuffer = new BYTE[csm_inputBufferSize];

		DWORD buffSize = fillBuffer(csm_inputBufferSize);

		m_pZipStream->next_in  = m_pInputBuffer;
		m_pZipStream->avail_in = buffSize;
		m_pZipStream->total_in = 0;
		inflateInit2(m_pZipStream, -MAX_WBITS);

		setStatus(Ok);
	}
	return true;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
void ZipSubRStream::detachStream()
{
	if (m_pZipStream != NULL) {
		// close out zip stream...
		inflateEnd(m_pZipStream);

		delete m_pZipStream;
		m_pZipStream = NULL;
	}
	delete [] m_pInputBuffer;
	m_pInputBuffer = NULL;
	delete [] m_pOutputBuffer;
	m_pOutputBuffer = NULL;

	m_pStream          = NULL;
	m_originalSlavePosition = 0;
	m_curSlavePosition = 0;
	m_uncompressedSize = 0;
	m_currentPosition  = 0;
	setStatus(Closed);
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
Stream* ZipSubRStream::getStream()
{
	return m_pStream;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param in_uncSize : 描述
 * \return 返回值的描述
 */
//--------------------------------------
void ZipSubRStream::setUncompressedSize(const DWORD in_uncSize)
{
	//AssertFatal(m_pStream != NULL, "error, no stream to set unc size for");

	m_uncompressedSize = in_uncSize;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param out_pBuffer : 描述
 * \param in_numBytes : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubRStream::_read(void *out_pBuffer, const DWORD in_numBytes)
{
	if (in_numBytes == 0)
		return true;

	AssertFatal(out_pBuffer != NULL, "NULL output buffer");
	if (getStatus() == Closed) {
		AssertFatal(false, "Attempted read from closed stream");
		return false;
	}

	if(m_pOutputBuffer)
	{
		size_t curPos = getPosition();
		size_t toRead = min(in_numBytes,m_uncompressedSize-curPos);
		memcpy(out_pBuffer,m_pOutputBuffer+curPos,toRead);
		setPosition(curPos + toRead);
		return true;
	}

	// Ok, we need to call inflate() until the output buffer is full.
	//  first, set up the output portion of the z_stream
	//
	m_pZipStream->next_out  = (Bytef*)out_pBuffer;
	m_pZipStream->avail_out = in_numBytes;
	m_pZipStream->total_out = 0;

	while (m_pZipStream->avail_out != 0) 
	{
		long retVal = Z_OK;

		if(m_pZipStream->avail_in == 0)
		{
			// check if there is more output pending
			inflate(m_pZipStream, Z_SYNC_FLUSH);

			if(m_pZipStream->total_out != in_numBytes)
			{
				// Need to provide more input bytes for the stream to read...
				DWORD buffSize = fillBuffer(csm_inputBufferSize);
				AssertFatal(buffSize != 0, "Must find a more graceful way to handle this");

				m_pZipStream->next_in  = m_pInputBuffer;
				m_pZipStream->avail_in = buffSize;
				m_pZipStream->total_in = 0;
			}
		}

		// need to get more?
		if(m_pZipStream->total_out != in_numBytes)
			retVal = inflate(m_pZipStream, Z_SYNC_FLUSH);

		AssertFatal(retVal != Z_BUF_ERROR, "Should never run into a buffer error");
		AssertFatal(retVal == Z_OK || retVal == Z_STREAM_END, "error in the stream");

		if (retVal == Z_STREAM_END) 
		{
			if (m_pZipStream->avail_out != 0)
				setStatus(EOS);
			else
				setStatus(Ok);
			m_currentPosition += m_pZipStream->total_out;
			return getStatus() == Ok;
		}
	}
	AssertFatal(m_pZipStream->total_out == in_numBytes,
		"Error, didn't finish the decompression!");

	// If we're here, everything went peachy...
	setStatus(Ok);
	m_currentPosition += m_pZipStream->total_out;

	return true;
}

//--------------------------------------
bool ZipSubRStream::hasCapability(const Capability in_cap) const
{
	return (csm_streamCaps & DWORD(in_cap)) != 0;
}

//--------------------------------------
DWORD ZipSubRStream::getPosition() const
{
	AssertFatal(m_pStream != NULL, "Error, not attached");

	return m_currentPosition;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param in_newPosition : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubRStream::setPosition(const DWORD in_newPosition)
{
	AssertFatal(m_pStream != NULL, "Error, not attached");

	if(m_pOutputBuffer)
	{
		if(in_newPosition < m_uncompressedSize)
		{
			m_currentPosition = in_newPosition;
			return true;
		}
		m_currentPosition = m_currentPosition;
		setStatus(EOS);
		return false;
	}

	if (in_newPosition == 0)
	{
		Stream* pStream = getStream();
		DWORD resetPosition = m_originalSlavePosition;
		DWORD uncompressedSize = m_uncompressedSize;
		detachStream();
		pStream->setPosition(resetPosition);
		attachStream(pStream);
		setUncompressedSize(uncompressedSize);
		return true;
	}
	else
	{
		//AssertFatal(false, "Not implemented!");
		// Erk.  How do we do this.
		if(in_newPosition < getPosition())
		{
			setPosition(0);
		}

		while(getPosition() < in_newPosition )
		{
			DWORD curNum = in_newPosition-getPosition();
			DWORD curReadNum = min((DWORD)4096,curNum);
			BYTE tmpData[4096];
			DWORD oldPos = getPosition();
			_read(tmpData,curReadNum);
			if(getPosition() == oldPos) 
			{
				//Assert(0);
				return false;
			}
		}
		
		Assert(in_newPosition == getPosition());
		return (in_newPosition == getPosition());
	}
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
DWORD ZipSubRStream::getSize()
{
	AssertFatal(m_pStream != NULL, "No stream to size()");
	AssertFatal(m_uncompressedSize != 0, "No data?  Properties probably not set...");

	return m_uncompressedSize;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param in_attemptSize : 描述
 * \return 返回值的描述
 */
//--------------------------------------
DWORD ZipSubRStream::fillBuffer(const DWORD in_attemptSize)
{
	AssertFatal(m_pStream != NULL, "No stream to fill from?");
	AssertFatal(m_pStream->getStatus() != Stream::Closed,
		"Fill from a closed stream?");

	DWORD streamSize = m_pStream->getSize();

	if(m_pStream->getPosition() != m_curSlavePosition)
		m_pStream->setPosition(m_curSlavePosition);

	DWORD actualReadSize = min(in_attemptSize,streamSize - m_curSlavePosition);

	if (m_pStream->read(m_pInputBuffer, actualReadSize)) {
		m_curSlavePosition += actualReadSize;
		return actualReadSize;
	} else {
		AssertFatal(false, "Read failed while trying to fill buffer");
		return 0;
	}
}


/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------------------------------------------
ZipSubWStream::ZipSubWStream()
: m_pStream(NULL),
m_currPosition(0),
m_pOutputBuffer(NULL),
m_pInputBuffer(NULL),
m_pZipStream(NULL)
{
	//
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
ZipSubWStream::~ZipSubWStream()
{
	detachStream();
	delete [] m_pOutputBuffer;
	delete [] m_pInputBuffer;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param io_pSlaveStream : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubWStream::attachStream(Stream* io_pSlaveStream)
{
	AssertFatal(io_pSlaveStream != NULL, "NULL Slave stream?");
	AssertFatal(m_pStream == NULL,       "Already attached!");

	m_pStream      = io_pSlaveStream;
	m_currPosition = 0;

	if(!m_pOutputBuffer)
		m_pOutputBuffer = new BYTE[csm_bufferSize];
	
	if(!m_pInputBuffer)
		m_pInputBuffer  = new BYTE[csm_bufferSize];

	// Initialize zipStream state...
	m_pZipStream = new z_stream_s;

	m_pZipStream->zalloc = Z_NULL;
	m_pZipStream->zfree  = Z_NULL;
	m_pZipStream->opaque = Z_NULL;

	m_pZipStream->next_in   = m_pInputBuffer;
	m_pZipStream->avail_in  = csm_bufferSize;
	m_pZipStream->total_in  = 0;
	m_pZipStream->next_out  = m_pOutputBuffer;
	m_pZipStream->avail_out = csm_bufferSize;
	m_pZipStream->total_out = 0;

	deflateInit2(m_pZipStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);

	setStatus(Ok);
	return true;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
void ZipSubWStream::detachStream()
{
	// Must finish...
	if (m_pZipStream != NULL) 
	{
		m_pZipStream->avail_in = 0;
		deflate(m_pZipStream, Z_FINISH);

		// write the remainder
		m_pStream->write(m_pOutputBuffer,csm_bufferSize - m_pZipStream->avail_out );

		// close out zip stream...
		deflateEnd(m_pZipStream);

		delete m_pZipStream;
		m_pZipStream = NULL;

		delete [] m_pInputBuffer;
		m_pInputBuffer  = NULL;
		delete [] m_pOutputBuffer;
		m_pOutputBuffer = NULL;
	}

	m_pStream      = NULL;
	m_currPosition = 0;
	setStatus(Closed);
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
//--------------------------------------
Stream* ZipSubWStream::getStream()
{
	return m_pStream;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param DWORD : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubWStream::_read(void*,const DWORD )
{
	AssertFatal(false, "Cannot read from a ZipSubWStream");

	setStatus(IllegalCall);
	return false;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param pBuffer : 描述
 * \param numBytes : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubWStream::_write(const void *pBuffer, const DWORD numBytes)
{
	if (numBytes == 0)
		return true;

	AssertFatal(pBuffer != NULL, "NULL input buffer");
	if (getStatus() == Closed) 
	{
		AssertFatal(false, "Attempted write to a closed stream");
		return false;
	}

	m_pZipStream->next_in = (BYTE*)pBuffer;
	m_pZipStream->avail_in = numBytes;

	// write as many bufferSize chunks as possible
	while(m_pZipStream->avail_in != 0)
	{
		if(m_pZipStream->avail_out == 0)
		{
			if(!m_pStream->write(m_pOutputBuffer, csm_bufferSize))
				return(false);

			m_pZipStream->next_out = m_pOutputBuffer;
			m_pZipStream->avail_out = csm_bufferSize;
		}

		long retVal = deflate(m_pZipStream, Z_NO_FLUSH);
		AssertFatal(retVal !=  Z_BUF_ERROR, "ZipSubWStream::_write: invalid buffer");
	}

	setStatus(Ok);
	m_currPosition += m_pZipStream->total_out;

	return true;
}

//--------------------------------------
bool ZipSubWStream::hasCapability(const Capability in_cap) const
{
	return (csm_streamCaps & DWORD(in_cap)) != 0;
}

//--------------------------------------
DWORD ZipSubWStream::getPosition() const
{
	AssertFatal(m_pStream != NULL, "Error, not attached");

	return m_currPosition;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \param  : 描述
 * \return 返回值的描述
 */
//--------------------------------------
bool ZipSubWStream::setPosition(const DWORD /*in_newPosition*/)
{
	AssertFatal(m_pStream != NULL, "Error, not attached");
	AssertFatal(false, "Not implemented!");

	// Erk.  How do we do this.
	return false;
}

/**
 * \brief 简短描述
 * 
 * 详细描述
 * 
 * \return 返回值的描述
 */
DWORD ZipSubWStream::getSize()
{
	AssertFatal(false, "Undecided how to implement this!");
	return 0;
}