// DIMEDeserializer.h: interface for the DIMEDeserializer 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.
//
//////////////////////////////////////////////////////////////////////
//
// DIMEDeserializer class - implementation of FSM based DIME deserializer.
// A setup call to Init() is required to set it up, and subsequent calls to
// Deserialize() present blocks of data for reading. Finished() returns true
// when the DIME payload has been received in full.
//  
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_DIMEDESERIALIZER_H__857DCEAC_40E4_4577_A410_3BF73A6372B2__INCLUDED_)
#define AFX_DIMEDESERIALIZER_H__857DCEAC_40E4_4577_A410_3BF73A6372B2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "DIMEPayload.h"
#include <vector>
using namespace std;

class DIMEDeserializer  
{
public:

	union Header32{
		unsigned long l;
		unsigned char c[4];
	};

	enum State {
		ST_START,
		ST_READ_HEADER,
		ST_READ_OPTIONS,
		ST_READ_CHUNK_OPTIONS,
		ST_READ_ID,
		ST_READ_TYPE,
		ST_OPEN_PAYLOAD,
		ST_DESERIALIZE_PAYLOAD,
		ST_NEXT_PAYLOAD,
		ST_CLOSE_PAYLOAD,
		ST_READ_CHUNK_HEADER,
		ST_DESERIALIZE_CHUNK,
		ST_FINISH,
		ST_ERROR
	};

	enum Event {
		EV_NULL,
		EV_DESERIALIZE,
		EV_HEADER_READ,
		EV_OPTIONS_READ,
		EV_ID_READ,
		EV_TYPE_READ,
		EV_PAYLOAD_OPENED,
		EV_PAYLOAD_CLOSED,
		EV_PAYLOAD_END,
		EV_CHUNK_END,
		EV_CHUNK_HEADER_READ,
		EV_MSG_END,
		EV_ERROR,
		EV_ERR_HANDLED
	};

	DIMEDeserializer();
	virtual ~DIMEDeserializer();

	bool Init(vector<DIMEPayload *> *pPayloads);
	bool Deserialize(	char *pszBuffer,
						unsigned long ulSize);
	bool Finished() { return m_State == ST_FINISH; }
	bool Error() { return m_State == ST_ERROR; }
	const wstring& GetLastError() { return m_wstrErrorMsg; }

protected:

	void OnEvent(Event e);

	Event ACT_Deserialize_Payload();
	Event ACT_Deserialize_Chunk();
	Event ACT_Read_Chunk_Header();
	Event ACT_Read_Header();
	Event ACT_Read_Options();
	Event ACT_Read_Chunk_Options();
	Event ACT_Read_Id();
	Event ACT_Read_Type();
	Event ACT_Open_Payload();
	Event ACT_Close_Payload();
	Event ACT_Error();
	
	bool ProcessOptions(DIMEPayload *pPayload);

	unsigned long					m_ulCurrentPayload;
	vector<DIMEPayload *>			*m_pPayloads;
	State							m_State;

	char							*m_pInputBuffer;
	unsigned long					m_ulInputBufferSize;
	char							*m_pCache;
	char							*m_pOptions;
	char							m_szHeader[32];
	unsigned long					m_ulBytesCached;
	unsigned long					m_ulCurrentPayloadSize;
	unsigned long					m_ulCurrentPayloadPaddingLength;
	unsigned long					m_ulPayloadBytesRemaining;
	string							m_strCurrentPayloadId;
	unsigned long					m_ulCurrentPayloadIdLength;
	unsigned long					m_ulCurrentPayloadIdPaddingLength;
	string							m_strCurrentPayloadType;
	unsigned long					m_ulCurrentPayloadTypeLength;
	unsigned long					m_ulCurrentPayloadTypePaddingLength;
	unsigned long					m_ulNbrBytesToSkip;
	unsigned long					m_ulCurrentPayloadTNF;
	unsigned long					m_ulCurrentOptionsLength;
	unsigned long					m_ulCurrentOptionsPaddingLength;
	bool							m_bCurrentPayloadChunked;
	bool							m_bEndOfMessage;
	wstring							m_wstrErrorMsg;

};

#define DIME_VERSION		0x08000000
#define MASK_VERSION		0xF8000000
#define MASK_TYPE_T			0x00F00000
#define MASK_OPTIONS_LENGTH	0x0000FFFF
#define MASK_ID_LENGTH		0xFFFF0000
#define MASK_TYPE_LENGTH	0x0000FFFF
#define MASK_MB_FLAG		0x04000000
#define MASK_ME_FLAG		0x02000000
#define MASK_CF_FLAG		0x01000000

#define HEADER_SIZE			12

#endif // !defined(AFX_DIMEDESERIALIZER_H__857DCEAC_40E4_4577_A410_3BF73A6372B2__INCLUDED_)
