// DIMEPayload.cpp: implementation of the DIMEPayload class.
//
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2002 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// DIMEPayload class - implementation of DIME payload class. This is 
// a wrapper for an IStorage interface pointer. Data is stored in a single
// stream with an empty name.
//  
//////////////////////////////////////////////////////////////////////


#include "stdafx.h"
#include "DIMEPayload.h"
#include "..\soap_source\charencode.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

DIMEPayload::DIMEPayload()
{
	m_pIStorage = NULL;
	m_pCurrentStream = NULL;
}

DIMEPayload::DIMEPayload(   IStorage *pIStorage,
							const string& strId,
							const string& strType,
							unsigned long ulTNF) :
								m_pIStorage(pIStorage),
								m_strId(strId),
								m_strType(strType),
								m_ulTNF(ulTNF)
{
	m_pIStorage->AddRef();
	m_pCurrentStream = NULL;
}


DIMEPayload::~DIMEPayload()
{
	if (m_pCurrentStream != NULL)
	{
		m_pCurrentStream->Release();
	}
	if (m_pIStorage != NULL)
	{
		m_pIStorage->Release();
	}
	list<DIMEOption *>::iterator iL;
	for (iL = m_listOptions.begin(); iL != m_listOptions.end(); iL++)
	{
		if (*iL != NULL)
		{
			delete *iL;
		}
	}
}

bool DIMEPayload::OpenForRead()
{
	if (m_pIStorage == NULL)
	{
		return false;
	}
	if (m_pCurrentStream != NULL)
	{
		m_pCurrentStream->Release();
		m_pCurrentStream = NULL;
	}
	// open stream
	wstring wstrId;
	UTF8ToWideString(m_strId, wstrId);
	HRESULT hRes = m_pIStorage->OpenStream( L"",
											NULL,
											STGM_READ | STGM_SHARE_EXCLUSIVE,
											0,
											&m_pCurrentStream);
	if (FAILED(hRes))
	{
		return false;
	}
	return true;
}

bool DIMEPayload::OpenForWrite()
{
	if (m_pIStorage == NULL)
	{
		return false;
	}
	if (m_pCurrentStream != NULL)
	{
		m_pCurrentStream->Release();
		m_pCurrentStream = NULL;
	}
	// open stream
	wstring wstrId;
	UTF8ToWideString(m_strId, wstrId);
	HRESULT hRes = m_pIStorage->CreateStream(   L"",
												STGM_CREATE | STGM_WRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
												0,
												NULL,
												&m_pCurrentStream);
	if (FAILED(hRes))
	{
		return false;
	}
	return true;
}

bool DIMEPayload::Close()
{
	if (m_pIStorage == NULL)
	{
		return false;
	}
	// close stream
	if (m_pCurrentStream != NULL)
	{
		m_pCurrentStream->Release();
		m_pCurrentStream = NULL;
	}
	return true;
}

unsigned long DIMEPayload::GetDataLength()
{
	if (m_pCurrentStream == NULL)
	{
		return 0;
	}
	STATSTG stats;
	HRESULT hRes = m_pCurrentStream->Stat(&stats, STATFLAG_NONAME);
	if (FAILED(hRes))
	{
		return 0;
	}
	return (unsigned long)stats.cbSize.QuadPart;
}

bool DIMEPayload::Read( char *pszBuffer,
						unsigned long ulBufferSize,
						unsigned long *pulBytesRead)
{
	if (m_pCurrentStream == NULL)
	{
		return false;
	}
	HRESULT hRes = m_pCurrentStream->Read(  pszBuffer,
											ulBufferSize,
											pulBytesRead);
	if (FAILED(hRes))
	{
		return false;
	}
	return true;
}

bool DIMEPayload::Write(char *pszBuffer,
						unsigned long ulBufferSize,
						unsigned long *pulBytesWritten)
{
	if (m_pCurrentStream == NULL)
	{
		return false;
	}
	HRESULT hRes = m_pCurrentStream->Write( pszBuffer,
											ulBufferSize,
											pulBytesWritten);
	if (FAILED(hRes))
	{
		return false;
	}
	return true;
}

unsigned long DIMEPayload::GetOptionsLength()
{
	unsigned long ulLength = 0;
	list<DIMEOption *>::iterator iL;
	for (iL = m_listOptions.begin(); iL != m_listOptions.end(); iL++)
	{
		if (*iL != NULL)
		{
			// length plus 4 bytes for header
			ulLength += ((*iL)->GetLength() + 4);
		}
	}
	return ulLength;
}

bool DIMEPayload::GetOptions(unsigned char *pOptions, unsigned long& ulLength)
{
	unsigned char *pWritePtr = pOptions;
	ulLength = 0;
	list<DIMEOption *>::iterator iL;
	for (iL = m_listOptions.begin(); iL != m_listOptions.end(); iL++)
	{
		if (*iL == NULL)
		{
			continue;
		}
		DIMEOption *pOption = *iL;
		// header
		Header32 ulHeader;
		ulHeader.l = pOption->GetType();
		ulHeader.l <<= 16;
		ulHeader.l |= pOption->GetLength();
		// write to buffer
		for (unsigned long j = 0; j < 4; j++)
		{
			pWritePtr[j] = ulHeader.c[3 - j];
		}
		pWritePtr += 4;
		ulLength += 4;
		// data
		memcpy(pWritePtr, pOption->GetData(), pOption->GetLength());
		pWritePtr += pOption->GetLength();
		ulLength += pOption->GetLength();
	}
	return true;
}

bool DIMEPayload::SetOptions(unsigned char *pOptions, unsigned long ulLength)
{
	Header32 ulHeader;
	unsigned char *pIndex = pOptions;
	unsigned char *pEnd = pIndex + ulLength;
	do
	{
		if (pEnd - pIndex < 4)
		{
			return false;
		}
		for (int j = 0; j < 4; j++)
		{
			ulHeader.c[3 - j] = pIndex[j];
		}
		pIndex += 4;
		unsigned long ulOptionLength = ulHeader.l & 0x0000FFFF;
		if (pIndex + ulOptionLength > pEnd)
		{
			return false;
		}
		unsigned long ulType = ulHeader.l >> 16;
		DIMEOption *pOption = new DIMEOption(ulType, ulOptionLength, pIndex);
		if (pOption == NULL)
		{
			return false;
		}
		m_listOptions.push_back(pOption);
		pIndex += ulOptionLength;
	} while (pIndex < pEnd);

	return true;
}

bool DIMEPayload::AddOption(DIMEOption *pOption)
{
	if (pOption == NULL)
	{
		return false;
	}
	GetOptionsList().push_back(pOption);
	return true;
}


