#include "header.h"

#include "DibCls.H"
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
#include <urlmon.h>

#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)

//=--------------------------------------------------------------------------=
// DIB Utitilty Classes
//=--------------------------------------------------------------------------=
// Not wholey generic but getting there...
//
// Notes:
//
CDibFile::CDibFile()
{
	m_headerSize = 0;
	m_bmi.p = 0;
}

CDibFile::~CDibFile()
{
	if( m_bmi.p )
		delete m_bmi.p;
}


DWORD CDibFile::CalcImageSize()
{
	DWORD & dw = m_bmi.p->bmiHeader.biSizeImage;
	if( dw == 0)
        dw = WIDTHBYTES((DWORD)m_bmi.p->bmiHeader.biWidth *
                m_bmi.p->bmiHeader.biBitCount) * m_bmi.p->bmiHeader.biHeight;

	return(dw);
}

HRESULT CDibFile::GetInfoHeader( IStream * strm )
{
	HRESULT hr = S_OK;
	m_bmi.bytes = new unsigned char[ m_headerSize ];

	if( !m_bmi.bytes )
		hr = E_OUTOFMEMORY;

	if( SUCCEEDED(hr) )
		hr = strm->Read(m_bmi.bytes,m_headerSize,0);

	if( SUCCEEDED(hr) )
		CalcImageSize();

	return(hr);
}

HRESULT CDibFile::GetFileHeader(IStream * strm)
{
	BITMAPFILEHEADER	bmfh;

	HRESULT	hr = strm->Read(&bmfh,sizeof(bmfh),0);
	
	if( SUCCEEDED(hr) && (bmfh.bfType != 0x4d42 ))
		hr = E_UNEXPECTED;

	if( SUCCEEDED(hr) )
		m_headerSize = bmfh.bfOffBits - sizeof(bmfh);

	return(hr);
}


CDibSection::CDibSection()
{
	m_bitsBase	= 0;
	m_current	= 0;
	m_memDC		= 0;
	m_handle	=
	m_oldBitmap = 0;
	m_w			=
	m_h			= 32;  // totally arbitrary
}

CDibSection::~CDibSection()
{
	if( m_memDC )
	{
		if( m_oldBitmap )
			::SelectObject( m_memDC, m_oldBitmap );

		::DeleteDC(m_memDC);
	}

	if( m_handle )
		::DeleteObject(m_handle);

}
	
	
HRESULT CDibSection::Create(CDibFile& dibFile)
{
	HRESULT				hr		= S_OK;
	BITMAPINFOHEADER *	bmih	= dibFile;	// will convert itself

	m_handle = ::CreateDIBSection(
					m_memDC,				// handle to device context
					dibFile,				// pointer to structure containing bitmap size,
											//	format, and color data
					DIB_RGB_COLORS,			// color data type indicator: RGB values or
											//	palette indices
					(void **)&m_bitsBase,	// pointer to variable to receive a pointer
											//	to the bitmap's bit values
					0,						// optional handle to a file mapping object
					0						// offset to the bitmap bit values
											//	within the file mapping object
					);

	if( !m_handle )
		hr = E_FAIL;
	
	if( SUCCEEDED(hr) )
	{
		m_oldBitmap = ::SelectObject( m_memDC, m_handle );
		
		if( !m_oldBitmap )
			hr = E_FAIL;
	}

	if( SUCCEEDED(hr) )
	{
		m_current = m_bitsBase;

		m_w = bmih->biWidth;
		m_h = bmih->biHeight;
		
		if( m_h < 0 )
			m_h *= -1;
	}
		
	return(hr);
}

HRESULT CDibSection::ReadFrom( IStream * strm, DWORD amount )
{
   DWORD    dwRead      = 0;
   DWORD    dwReadTotal = 0;
   HRESULT  hr;

   do
   {
      hr = strm->Read(m_current,amount,&dwRead);

   	if( SUCCEEDED(hr) || hr == E_PENDING )
      {
         m_current += dwRead;
         dwReadTotal += dwRead;
      }
   }
   while ( (hr == S_OK) && (dwReadTotal <= amount) );

   return (hr);
}


HRESULT CDibSection::Setup(HDC hdc)
{
	m_memDC = ::CreateCompatibleDC(hdc);

	return( m_memDC ? NOERROR : E_FAIL );
}


HRESULT	CDibSection::PaintTo(HDC hdc, int x, int y)
{
	BOOL b = BitBlt(
				 hdc,		// handle to destination device context
				 x,			// x-coordinate of destination rectangle's upper-left corner
				 y,			// x-coordinate of destination rectangle's upper-left corner
				 m_w,		// width of destination rectangle
				 m_h,		// height of destination rectangle
				 m_memDC,	// handle to source device context
				 0,			// x-coordinate of source rectangle's upper-left corner
				 0,			// y-coordinate of source rectangle's upper-left corner
				 SRCCOPY	// raster operation code
				);

	return( b ? NOERROR : E_FAIL );
}

HRESULT	CDibSection::GetSize(SIZEL &sz)
{
	sz.cx = m_w;
	sz.cy = m_h;

	return(S_OK);
}