// DataSet.cpp: implementation of the CaplPacket class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "aplPacket.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// Максимальный размер файла хранимого в памяти (если больше, то во временном файле)

//#define APL_MAX_FILE_SIZE_IN_MEMORY  32
#define APL_MAX_FILE_SIZE_IN_MEMORY  64*1024*1024
//#define APL_MAX_FILE_SIZE_IN_MEMORY  3*1024*1024*1024

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

/*
void SaveStr2Buf(CString str, BYTE  *pBuf, int &index, bool bANSI = true)
{
	int i;
	int *pInt;
	pInt = (int*)&pBuf[index];
	*pInt = str.GetLength();
	index+=sizeof(int);

#ifdef _UNICODE
	if (bANSI)
	{
		// переводим строку в ANSI
		CaplStringAdapter sAdapter(str);
		LPCSTR pBufANSI = (LPCSTR)sAdapter;
		for(i=0; i<str.GetLength(); i++)
			pBuf[index++]=pBufANSI[i];
		pBuf[index++]='\0';
	}
	else
	{
		// пишем Unicode-строку
		wcsncpy((LPWSTR)(pBuf+index), (LPCWSTR)str, str.GetLength());
		index += str.GetLength()*sizeof(wchar_t);
		((LPWSTR)(pBuf+index))[0] = L'\0';
	}
#else
	for(i=0; i<str.GetLength(); i++)
		pBuf[index++]=str[i];
	pBuf[index++]='\0';
#endif
}

void SaveInt2Buf(int val, BYTE  *pBuf, int &index)
{
	int *pInt;
	pInt = (int*)&pBuf[index];
	*pInt = val;
	index+=sizeof(int);
}
*/
void LoadStrFromBuf(CString &str, BYTE  *pBuf, int &index, bool bANSI = true)
{
	size_t i, cnt;
	int *pInt;
	pInt = (int*)&pBuf[index];
	cnt = *pInt;
	index+=sizeof(int);

#ifdef _UNICODE
	if (bANSI)
	{
		// переводим из ANSI-строки в Unicode
		CaplStringAdapter sAdapter((LPCSTR)pBuf + index);
		str = (LPCWSTR)sAdapter;
		index += (cnt+1)*sizeof(TCHAR);
	}
	else
	{
		str.Empty();
		TCHAR *buf = str.GetBufferSetLength(cnt+1);

		for(i=0; i<(cnt+1)*sizeof(TCHAR); i++)
			buf[i]=pBuf[index++];

		str.ReleaseBuffer();
	}
#else
	str.Empty();
	TCHAR *buf = str.GetBufferSetLength(cnt+1);

	for(i=0; i<cnt+1; i++)
		buf[i]=pBuf[index++];

	str.ReleaseBuffer();
#endif
}

void LoadIntFromBuf(int &val, BYTE  *pBuf, int &index)
{
	int *pInt;
	pInt = (int*)&pBuf[index];
	val = *pInt;
	index+=sizeof(int);
}

//////////////////////////////////////////////////////////////////////////
CSignSert::CSignSert(CaplPacket	*pPacket)
{
	ASSERT(pPacket);
	m_pPacket = pPacket;
	
	m_sCertBS.Empty();
	m_sCertSN.Empty();
	m_sPersonName.Empty();

	m_pPacket->m_Sertificates.Add(this);	
}

CSignSert::~CSignSert()
{
	if(m_pPacket)
	{
		int i;
		for(i=0; i<m_pPacket->m_Sertificates.GetSize(); i++)
		{
			if(m_pPacket->m_Sertificates[i]==this)
			{
				m_pPacket->m_Sertificates.RemoveAt(i);
				break;
			}
		}
	}
}

bool CSignSert::Load(CBinaryFile &file)
{
	CString sRoles;
	CaplCryptographicManager Crypto;

	// получаем информацию в строке
	file.Read(m_sCertBS); 

	// строку переводим в байты
	int FileSize = m_sCertBS.GetLength()/2;
	LPTSTR szContainerCA = m_sCertBS.GetBuffer();
	BYTE *pbCertData = new BYTE[FileSize];
	
	Crypto.StrToByte(m_sCertBS.GetLength(), CaplStringAdapter(szContainerCA), pbCertData);
	m_sCertBS.ReleaseBuffer();

	// получаем данные о сертификате
	COleDateTime t1, t2;
	Crypto.GetCertSubjectNameAndSN(pbCertData, FileSize, m_sPersonName, m_sCertSN, sRoles, t1, t2);

	if(pbCertData) delete [] pbCertData;
	return true;
}

void CSignSert::Save(CBinaryFile &file)
{
	file.Write(m_sCertBS);	
}
UINT64 CSignSert::GetBufSize(bool bUseAdditionalParam)
{
	int size = sizeof(UINT32);
	size+=m_sCertBS.GetLength()+1;
	return size;
}

bool CSignSert::SaveToBuf(CaplSignBuf &signBuf, bool bUseAdditionalParam)
{
	signBuf.Add(m_sCertBS);
	return true;
}

bool CSignSert::LoadFromBuf(BYTE  *pBuf, int &index)
{
	LoadStrFromBuf(m_sCertBS, pBuf, index);
	return true;
}
//////////////////////////////////////////////////////////////////////////
CDataSetSign::CDataSetSign(CaplPacket *pPacket)
{
	ASSERT(pPacket);
	m_bNewSign = true;
	m_pPacket = pPacket;
	m_pPacket->m_DataSetSigns.Add(this);
}

CDataSetSign::~CDataSetSign()
{
	if(m_pPacket)
	{
		int i;
		for(i=0; i<m_pPacket->m_DataSetSigns.GetSize(); i++)
		{
			if(m_pPacket->m_DataSetSigns[i]==this)
			{
				m_pPacket->m_DataSetSigns.RemoveAt(i);
				break;
			}
		}
	}
}

bool CDataSetSign::Load(CBinaryFile &file, int ds_offset, int sert_offset)
{
	UINT32 dataset_index=0;
	UINT32 sert_index=0;
	CString buf;

	if(!file.Read(dataset_index)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(((UINT32)m_pPacket->m_DataSets.GetSize())<dataset_index+ds_offset || dataset_index+ds_offset<1) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(sert_index)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(((UINT32)m_pPacket->m_Sertificates.GetSize())<=sert_index+sert_offset || sert_index+sert_offset<0) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sStatus)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sRole)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sDate)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sComment)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	
	if(!file.Read(m_sHashSystem)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sHashBS)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	
	if(!file.Read(m_sSignSystem)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(m_sSignBS)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	if(!file.Read(buf)) throw(APL_LOAD_DATASETSIGN_FROM_FILE_ERROR);
	buf == _T("1") ? m_bNewSign=true : m_bNewSign = false;

	m_pDataSet = m_pPacket->m_DataSets[dataset_index-1+ds_offset];
	m_pSertificate = m_pPacket->m_Sertificates[sert_index+sert_offset];

	return true;
}

bool CDataSetSign::Save(CBinaryFile &file)
{
	UINT32 i;
	UINT32 dataset_index = -1;
	UINT32 sert_index = -1;
	
	for(i=0; i<(UINT32)m_pPacket->m_DataSets.GetSize(); i++)
	{
		if(m_pPacket->m_DataSets[i]==m_pDataSet)
		{
			dataset_index=i+1;
			break;
		}
	}
	if(dataset_index<1) throw(APL_SAVE_DATASETSIGN_TO_FILE_ERROR);
	for(i=0; i<(UINT32)m_pPacket->m_Sertificates.GetSize(); i++)
	{
		if(m_pPacket->m_Sertificates[i]==m_pSertificate)
		{
			sert_index=i;
			break;
		}
	}
	if(sert_index<0) throw(APL_SAVE_DATASETSIGN_TO_FILE_ERROR);

	file.Write(dataset_index);
	file.Write(sert_index);
	file.Write(m_sStatus);
	file.Write(m_sRole);
	file.Write(m_sDate);
	file.Write(m_sComment);
	
	file.Write(m_sHashSystem);
	file.Write(m_sHashBS);
	
	file.Write(m_sSignSystem);
	file.Write(m_sSignBS);
	m_bNewSign ? file.Write(_T("1")) : file.Write(_T("0"));
	
	return true;
}

UINT64 CDataSetSign::GetBufSize(bool bUseAdditionalParam)
{
	UINT64 size;
	size = sizeof(UINT32)*10;
	size+= m_sStatus.GetLength()+1;
	size+= m_sRole.GetLength()+1;
	size+= m_sDate.GetLength()+1;
	size+= m_sComment.GetLength()+1;
	
	size+= m_sHashSystem.GetLength()+1;
	size+= m_sHashBS.GetLength()+1;
	
	size+= m_sSignSystem.GetLength()+1;
	size+= m_sSignBS.GetLength()+1;

	return size;
}

bool CDataSetSign::SaveToBuf(CaplSignBuf &signBuf, bool bUseAdditionalParam)
{
	int i;
	UINT32 dataset_index = -1;
	UINT32 sert_index = -1;
	
	for(i=0; i<m_pPacket->m_DataSets.GetSize(); i++)
	{
		if(m_pPacket->m_DataSets[i]==m_pDataSet)
		{
			dataset_index=i+1;
			break;
		}
	}
	if(dataset_index<1) throw(APL_SAVE_DATASETSIGN_TO_BUF_ERROR);
	for(i=0; i<m_pPacket->m_Sertificates.GetSize(); i++)
	{
		if(m_pPacket->m_Sertificates[i]==m_pSertificate)
		{
			sert_index=i;
			break;
		}
	}
	if(sert_index<0) throw(APL_SAVE_DATASETSIGN_TO_BUF_ERROR);
	
	signBuf.Add(dataset_index);
	signBuf.Add(sert_index);
	signBuf.Add(m_sStatus);
	signBuf.Add(m_sRole);
	signBuf.Add(m_sDate);
	signBuf.Add(m_sComment);
	
	signBuf.Add(m_sHashSystem);
	signBuf.Add(m_sHashBS);
	
	signBuf.Add(m_sSignSystem);
	signBuf.Add(m_sSignBS);

	return true;
}

bool CDataSetSign::LoadFromBuf(BYTE  *pBuf, int &index, int ds_offset, int sert_offset)
{
	int dataset_index = -1;
	int sert_index = -1;
	
	LoadIntFromBuf(dataset_index, pBuf, index);
	LoadIntFromBuf(sert_index, pBuf, index);

	if(m_pPacket->m_DataSets.GetSize()<dataset_index+ds_offset || dataset_index+ds_offset<1) throw(APL_LOAD_DATASETSIGN_FROM_BUF_ERROR);
	if(m_pPacket->m_Sertificates.GetSize()<=sert_index+sert_offset || sert_index+sert_offset<0) throw(APL_LOAD_DATASETSIGN_FROM_BUF_ERROR);

	m_pDataSet = m_pPacket->m_DataSets[dataset_index-1];
	m_pSertificate = m_pPacket->m_Sertificates[sert_index];
	
	LoadStrFromBuf(m_sStatus, pBuf, index);
	LoadStrFromBuf(m_sRole, pBuf, index);
	LoadStrFromBuf(m_sDate, pBuf, index);
	LoadStrFromBuf(m_sComment, pBuf, index);
	
	LoadStrFromBuf(m_sHashSystem, pBuf, index);
	LoadStrFromBuf(m_sHashBS, pBuf, index);
	
	LoadStrFromBuf(m_sSignSystem, pBuf, index);
	LoadStrFromBuf(m_sSignBS, pBuf, index);
	
	return true;
}
//////////////////////////////////////////////////////////////////////////
CDataSetParam::CDataSetParam() : m_sName(_T("")), m_sValue(_T("")), m_bANSI(true)
{
}

CDataSetParam::CDataSetParam(LPCTSTR sName, LPCTSTR sValue, bool bANSI /*= true*/) : m_sName(_T("")), m_sValue(_T("")), m_bANSI(true)
{
	if (sName)
		m_sName = sName;
	if (sValue)
		m_sValue = sValue;
	m_bANSI = bANSI;
}

CDataSetParam::~CDataSetParam()
{
}

bool CDataSetParam::Load(CBinaryFile &file)
{
	if(!file.Read(m_sName)) throw(APL_LOAD_DATASETPARAM_FROM_FILE_ERROR);
	if(!file.Read(m_sValue)) throw(APL_LOAD_DATASETPARAM_FROM_FILE_ERROR);

	return true;
}

bool CDataSetParam::Save(CBinaryFile &file)
{
	file.Write(m_sName);
	file.Write(m_sValue);
	
	return true;
}
UINT64 CDataSetParam::GetBufSize(bool bUseAdditionalParam)
{
	UINT64 size = sizeof(UINT32)*2;
	size+=m_sName.GetLength()+1;
	size+=m_sValue.GetLength()+1;

	return size;
}

bool CDataSetParam::SaveToBuf(CaplSignBuf &signBuf, bool bUseAdditionalParam)
{
	signBuf.Add(m_sName,m_bANSI);
	signBuf.Add(m_sValue,m_bANSI);
	return true;
}

bool CDataSetParam::LoadFromBuf(BYTE  *pBuf, int &index)
{
	LoadStrFromBuf(m_sName, pBuf, index, m_bANSI);
	LoadStrFromBuf(m_sValue, pBuf, index, m_bANSI);
	
	return true;
}
/************************************************************************/
/*                           CDataSet                                   */
/************************************************************************/
CDataSet::CDataSet(CaplPacket *pPacket, CDataSet *pParent, bool bANSI /*= true*/)
{
	ASSERT(pPacket);
	m_item=0;
	m_bANSI = bANSI;
	m_pPacket = pPacket;
	m_pParent = pParent;
	if(pParent)
	{
		if(pParent->IsFolder())
			((CFolderDataSet*)pParent)->m_Content.Add(this);
	}
	m_pPacket->m_DataSets.Add(this);
}

CDataSet::~CDataSet()
{
	if(m_pPacket)
	{
		int i;
		for(i=0; i<m_pPacket->m_DataSets.GetSize(); i++)
		{
			if(m_pPacket->m_DataSets[i]==this)
			{
				m_pPacket->m_DataSets.RemoveAt(i);
				break;
			}
		}
	}
	if(m_pParent)
	{
		if(m_pParent->IsFolder())
		{
			CFolderDataSet* pFolder = (CFolderDataSet*)m_pParent;
			int i;
			for(i=0; i<pFolder->m_Content.GetSize(); i++)
			{
				if(pFolder->m_Content[i]==this)
				{
					pFolder->m_Content.RemoveAt(i);
					break;
				}
			}
		}
	}

	Clear();
}

void CDataSet::Clear()
{
	int i;
	for(i=0; i<m_Parametrs.GetSize(); i++)
		delete m_Parametrs[i];
	m_Parametrs.RemoveAll();

	m_sName.Empty();
	m_sCompress_method.Empty();
	m_sCrypt_method.Empty();
}

bool CDataSet::GetParamValueBN(LPCTSTR lpName, CString &sValue)
{
	sValue.Empty();
	int i;
	for(i=0; i<m_Parametrs.GetSize(); i++)
	{
		if(m_Parametrs[i]->m_sName.CompareNoCase(lpName)==0) 
		{
			sValue = m_Parametrs[i]->m_sValue;
			return true;
		}
	}

	return false;
}

bool CDataSet::SetParamValueBN(LPCTSTR lpName, LPCTSTR sValue)
{
	int i;
	for(i=0; i<m_Parametrs.GetSize(); i++)
	{
		if(m_Parametrs[i]->m_sName.CompareNoCase(lpName)==0) 
		{
			m_Parametrs[i]->m_sValue = sValue;
			return true;
		}
	}

	m_Parametrs.Add(new CDataSetParam(lpName, sValue, m_bANSI));
	return true;
}

int CDataSet::CheckSigns(bool bShowMessages)
{
	if(m_pPacket==NULL) return APL_CRYPT_UNKNOWN_ERROR;
	int i;
	CDataSetSign *pSign = NULL;
	//щем мою подпись
	for(i=0; i<m_pPacket->m_DataSetSigns.GetSize(); i++)
	{
		if(m_pPacket->m_DataSetSigns[i]->m_pDataSet==this)
		{
			pSign = m_pPacket->m_DataSetSigns[i];
			break;
		}
	}
	if(pSign==NULL) 
	{
		if(bShowMessages) MessageBox(0, APL_T("Объект не подписан."), APL_T("Нет подписи"), MB_ICONINFORMATION);
		return APL_CRYPT_NO_SIGN;
	}

	CString sHash;
	CaplCryptographicManager Crypto;
	CaplSignBuf signBuf;

	int index = 0;
	int size=0;

	long wdlg=0;
	
	wdlg=aplStartWaitDlg(_T("Подготовка данных для проверки..."));

	SaveToBuf(signBuf, pSign->m_bNewSign);
	
	aplEndWaitDlg(wdlg); wdlg=0;

	if(signBuf.GetAllDataSize()>0xfffffffe) 
	{
		if(bShowMessages)AfxMessageBox(APL_T("Подпись данных > 4 Гб. не поддерживается в этой версии."), MB_ICONSTOP|MB_OK);
		return APL_CRYPT_UNKNOWN_ERROR;
	}
	
	wdlg=aplStartWaitDlg(_T("Вычисление хэш-а..."));

	Crypto.GetHash(signBuf.GetData(), signBuf.GetDataSize(), LPCTSTR(pSign->m_sSignSystem),sHash);

	aplEndWaitDlg(wdlg); wdlg=0;


	//LPCTSTR szSystem = pSign->m_sSignSystem.GetBuffer();
	//Crypto.GetBufHash(pBuf, size, sHash, 0, szSystem);
	//pSign->m_sSignSystem.ReleaseBuffer();	

	CString sMessage;
	if(sHash.CompareNoCase(pSign->m_sHashBS))
	{
		if(bShowMessages)
		{
			sMessage.Format(CaplTranslate::Translate(_T("Подпись \"%s\": %s %s %s %s\n\n")
				_T("Подписанный объект был изменен. Подпись неверна.")),
				pSign->m_pDataSet->m_sName,
				pSign->m_sStatus,
				pSign->m_sRole,
				pSign->m_pSertificate->m_sPersonName,
				pSign->m_sDate);
			AfxMessageBox(sMessage, MB_ICONERROR|MB_OK);
		}
		return APL_CRYPT_INVALID_HASH;
	}
	else
	{
		DWORD const dwCertLen= pSign->m_pSertificate->m_sCertBS.GetLength()/2;
		BYTE* pbCertBlob= new BYTE [dwCertLen+1];
		Crypto.StrToByte(pSign->m_pSertificate->m_sCertBS.GetLength(), CaplStringAdapter(pSign->m_pSertificate->m_sCertBS), pbCertBlob);

		int nResult = APL_CRYPT_NO_ERROR;

		wdlg=aplStartWaitDlg(_T("Проверка подписи ..."));


		if(pSign->m_sSignSystem == APL_CRYPT_MGR)
		{
			nResult = Crypto.rsa_CheckSign(signBuf.GetData(), signBuf.GetDataSize(), pSign->m_sHashBS, pbCertBlob, dwCertLen, pSign->m_sSignBS, 0, 0);
		}
		else if(pSign->m_sSignSystem == APL_CRYPTO_PRO_34_10_2001)
		{
			nResult = Crypto.csp_CheckSign(signBuf.GetData(), signBuf.GetDataSize(), pSign->m_sHashBS, pbCertBlob, dwCertLen, pSign->m_sSignBS, 0, 0, APL_CSP_2001);
		}
		else if(pSign->m_sSignSystem == APL_CRYPTO_PRO_34_10_2012)
		{
			nResult = Crypto.csp_CheckSign(signBuf.GetData(), signBuf.GetDataSize(), pSign->m_sHashBS, pbCertBlob, dwCertLen, pSign->m_sSignBS, 0, 0, APL_CSP_2012);
		}

		aplEndWaitDlg(wdlg); wdlg=0;

		delete pbCertBlob; pbCertBlob=0;

		if(nResult != APL_CRYPT_NO_ERROR)
		{
			if(bShowMessages)
			{
				sMessage.Format(CaplTranslate::Translate(_T("Подпись \"%s\": %s %s %s %s\n\n")
					_T("Подпись неверна.")),
					pSign->m_pDataSet->m_sName,
					pSign->m_sStatus,
					pSign->m_sRole,
					pSign->m_pSertificate->m_sPersonName,
					pSign->m_sDate);
				AfxMessageBox(sMessage, MB_ICONERROR|MB_OK);
			}

			return APL_CRYPT_INVALID_SIGNATURE;
		}
	}

	if(bShowMessages)
		AfxMessageBox(APL_T("Подпись верна."), MB_ICONINFORMATION|MB_OK);

	
	return APL_CRYPT_NO_ERROR;
}

void CDataSet::SetANSI(bool bANSI)
{
	m_bANSI = bANSI;

	for(int i=0; i<m_Parametrs.GetSize(); ++i)
	{
		m_Parametrs[i]->SetANSI(bANSI);
	}
}

/************************************************************************/
/*                       CFolderDataSet                                 */
/************************************************************************/
CFolderDataSet::CFolderDataSet(CaplPacket *pPacket, CDataSet *pParent, bool bANSI /*= true*/):CDataSet(pPacket, pParent, bANSI)
{
}

CFolderDataSet::~CFolderDataSet()
{
	if(m_pPacket)
	{
		int i;
		for(i=0; i<m_pPacket->m_DataSets.GetSize(); i++)
		{
			if(m_pPacket->m_DataSets[i]==this)
			{
				m_pPacket->m_DataSets.RemoveAt(i);
				break;
			}
		}
	}
	if(m_pParent)
	{
		if(m_pParent->IsFolder())
		{
			CFolderDataSet* pFolder = (CFolderDataSet*)m_pParent;
			int i;
			for(i=0; i<pFolder->m_Content.GetSize(); i++)
			{
				if(pFolder->m_Content[i]==this)
				{
					pFolder->m_Content.RemoveAt(i);
					break;
				}
			}
		}
	}

	Clear();
}

bool CFolderDataSet::Load(CBinaryFile &file)
{
	Clear();

	UINT32 i,k;
	CDataSetParam *pParam;
	CDataSet	*pChild;

	if(!file.Read(m_sName)) throw(APL_LOAD_FOLDERDATASET_FROM_FILE_ERROR);
	if(!file.Read(m_sCompress_method)) throw(APL_LOAD_FOLDERDATASET_FROM_FILE_ERROR);
	if(!file.Read(m_sCrypt_method)) throw(APL_LOAD_FOLDERDATASET_FROM_FILE_ERROR);
	
	// Чтение параметров
	if(!file.Read(k)) throw(APL_LOAD_FOLDERDATASET_FROM_FILE_ERROR);
	
	for(i=0;i<k;i++)
	{
		pParam = new CDataSetParam(NULL, NULL, m_bANSI);
		pParam->Load(file);
		m_Parametrs.Add(pParam);
	}
	
	// Чтение входящих DataSet
	if(!file.Read(k)) throw(APL_LOAD_FOLDERDATASET_FROM_FILE_ERROR);

	for(i=0;i<k;i++)
	{
		bool bFolder(false);
#ifdef _UNICODE
		if (m_bANSI)
		{
			bFolder = (file.Read()=='D');
		}
		else
		{
			wchar_t c;
			file.Read(c);
			bFolder = (c==L'D');
		}
#else
		bFolder = (file.Read()=='D');
#endif

		if(bFolder)
			pChild = new CFolderDataSet(m_pPacket, this, m_bANSI);
		else
			pChild = new CFileDataSet(m_pPacket, this, m_bANSI);
		pChild->Load(file);
	}

	return true;
}

bool CFolderDataSet::Save(CBinaryFile &file)
{
	int i;
#ifdef _UNICODE
	if (m_bANSI)
	{
		file.Write('D');
	}
	else
	{
		file.Write(L'D');
	}
#else
	file.Write('D');
#endif
	
	file.Write(m_sName);
	file.Write(m_sCompress_method);
	file.Write(m_sCrypt_method);
	
	// Чтение параметров
	file.Write((UINT32)m_Parametrs.GetSize());
	for(i=0; i<m_Parametrs.GetSize(); i++)
		m_Parametrs[i]->Save(file);
	
	// Чтение входящих DataSet
	file.Write((UINT32)m_Content.GetSize());
	for(i=0;i<m_Content.GetSize();i++)
		m_Content[i]->Save(file);
	
	return true;
}

void CFolderDataSet::Clear()
{
	CDataSet::Clear();

	while(m_Content.GetSize()>0)
		delete m_Content[0];
}

bool CFolderDataSet::LoadItem(LPCTSTR lpszPath, bool addFileParam)
{
	CString sPath(lpszPath);
	sPath.TrimRight(_T("\\"));
	
	int ind = sPath.ReverseFind(_T('\\'));
	if(ind>-1)
		m_sName = sPath.Right(sPath.GetLength()-ind-1);
	
	CFileFind ff;
	BOOL ContainFiles = ff.FindFile(sPath+_T("\\*.*"));
	CString DirName;
	CDataSet *pDS;
	while(ContainFiles)
	{
		ContainFiles = ff.FindNextFile();
		if(ff.IsDots()) continue;
		if(ff.IsDirectory())
			pDS = new CFolderDataSet(m_pPacket, this, m_bANSI);
		else
			pDS = new CFileDataSet(m_pPacket, this, m_bANSI);
		pDS->LoadItem(ff.GetFilePath(), addFileParam);
	}

	return true;
}

UINT64 CFolderDataSet::GetBufSize(bool bUseAdditionalParam)
{
	int i;
	UINT64 size = m_bANSI?1:sizeof(TCHAR);//file.Write('D');
	size+=sizeof(UINT32)*3;
	size+=(m_sName.GetLength()+1)*(m_bANSI?1:sizeof(TCHAR));//file.Write(m_sName);
	size+=(m_sCompress_method.GetLength()+1)*(m_bANSI?1:sizeof(TCHAR));//file.Write(m_sCompress_method);
	size+=(m_sCrypt_method.GetLength()+1)*(m_bANSI?1:sizeof(TCHAR));//file.Write(m_sCrypt_method);
	
	size+=sizeof(UINT32);//file.Write(m_Parametrs.GetSize());
	for(i=0; i<m_Parametrs.GetSize(); i++)
		size+=m_Parametrs[i]->GetBufSize();//m_Parametrs[i]->Save(file);
	
	// Чтение входящих DataSet
	size+=sizeof(UINT32);//file.Write(m_Content.GetSize());
	for(i=0;i<m_Content.GetSize();i++)
		size+=m_Content[i]->GetBufSize();//m_Content[i]->Save(file);
	
	return size;
}

bool CFolderDataSet::SaveToBuf(CaplSignBuf &signBuf, bool bUseAdditionalParam)
{
	int i;
#ifdef _UNICODE
	if (m_bANSI)
	{
		signBuf.Add('D');
	}
	else
	{
		wchar_t wc= L'D';
		signBuf.Add((BYTE*)&wc,sizeof(wc));
	}
#else
	signBuf.Add('D');
#endif
	signBuf.Add(m_sName, m_bANSI);
	signBuf.Add(m_sCompress_method, m_bANSI);
	signBuf.Add(m_sCrypt_method, m_bANSI);
	
	signBuf.Add((UINT32)m_Parametrs.GetSize());
	for(i=0; i<m_Parametrs.GetSize(); i++)
		m_Parametrs[i]->SaveToBuf(signBuf);
	
	signBuf.Add((UINT32)m_Content.GetSize());
	for(i=0;i<m_Content.GetSize();i++)
		m_Content[i]->SaveToBuf(signBuf);

	return true;
}

bool CFolderDataSet::LoadFromBuf(BYTE  *pBuf, int &index)
{
	int i, cnt;
	Clear();

	LoadStrFromBuf(m_sName, pBuf, index);
	LoadStrFromBuf(m_sCompress_method, pBuf, index);
	LoadStrFromBuf(m_sCrypt_method, pBuf, index);
	
	CDataSetParam *pParam;
	LoadIntFromBuf(cnt, pBuf, index);
	for(i=0; i<cnt; i++)
	{
		pParam = new CDataSetParam(NULL, NULL, m_bANSI);
		pParam->LoadFromBuf(pBuf, index);
		m_Parametrs.Add(pParam);
	}
	
	CDataSet *pDS;
	LoadIntFromBuf(cnt, pBuf, index);
	for(i=0;i<cnt;i++)
	{
		if(((TCHAR*)pBuf)[index+=sizeof(TCHAR)]==_T('D'))
			pDS = new CFolderDataSet(m_pPacket, this, m_bANSI);
		else
			pDS = new CFileDataSet(m_pPacket, this, m_bANSI);
		pDS->LoadFromBuf(pBuf, index);
	}
	
	return true;
}

bool CFolderDataSet::SaveFiles(LPCTSTR lpszPathName)
{
	CString sPath = lpszPathName;
	if(lpszPathName!=0)
	{
		sPath+=m_sName;
		sPath+=_T('\\');
		CreateDirectory(sPath, 0);
	}
	else
	{
		CaplSelectFolderDialog dlg(FALSE, _T(""), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, NULL, NULL);
		if(dlg.DoModal()==IDOK)
			sPath = dlg.GetSelectedPath();
	}
	if(!sPath.IsEmpty())
	{
		for(int i=0;i< m_Content.GetSize();i++)
		{
			if(!m_Content[i]->SaveFiles(sPath))
				return false;
		}
	}
	
	return true;
}
/************************************************************************/
/*                        CFileDataSet                                  */
/************************************************************************/
CFileDataSet::CFileDataSet(CaplPacket *pPacket, CDataSet *pParent, bool bANSI /*= true*/):CDataSet(pPacket, pParent, bANSI)
{	
	m_pData = NULL;
	Clear();
}

CFileDataSet::~CFileDataSet()
{
	if(m_pPacket)
	{
		int i;
		for(i=0; i<m_pPacket->m_DataSets.GetSize(); i++)
		{
			if(m_pPacket->m_DataSets[i]==this)
			{
				m_pPacket->m_DataSets.RemoveAt(i);
				break;
			}
		}
	}
	if(m_pParent)
	{
		if(m_pParent->IsFolder())
		{
			CFolderDataSet* pFolder = (CFolderDataSet*)m_pParent;
			int i;
			for(i=0; i<pFolder->m_Content.GetSize(); i++)
			{
				if(pFolder->m_Content[i]==this)
				{
					pFolder->m_Content.RemoveAt(i);
					break;
				}
			}
		}
	}

	Clear();
}

bool CFileDataSet::LoadItem(LPCTSTR lpszPath, bool addFileParam)
{
	CFile file;
	CFileStatus fStatus;

	if(!file.Open(lpszPath, CFile::modeRead)) return false;
	file.GetStatus(fStatus);
	ULONGLONG fsize=file.GetLength();

	if(fsize>=0xfffffbff)  // 4Gb - 1024 на реквизиты
	{
		file.Close();
		AfxMessageBox(_T("Текущая версия не поддерживает файлы размером > 4 Гб.!"),MB_ICONSTOP|MB_OK);
		return false;
	}

	m_DataSize = (UINT32)fsize;
	m_sName = file.GetFileName();

	if (m_DataSize>APL_MAX_FILE_SIZE_IN_MEMORY) 
	{
		file.Close();
		aplGetTempFileName(_T("winetd"),_T("tmp"),m_sTempDataFile);
		if(m_sTempDataFile==_T("")) {AfxMessageBox(_T("Ошибка создания временного файла"),MB_ICONSTOP); false;}

		long wdlg=aplStartWaitDlg( APL_T("Копирование файла..."));
		bool bCopy=CaplFile::CopyFile(lpszPath,m_sTempDataFile,true);
		aplEndWaitDlg(wdlg);

		if(!bCopy)
		{
			AfxMessageBox(_T("Ошибка копирования файла!\n\nВозможно во временной папке недостаточно места."),MB_ICONSTOP);
			return false;
		}
		::SetFileAttributes(m_sTempDataFile,FILE_ATTRIBUTE_READONLY);
	}
	else
	{
		m_pData = new char[m_DataSize];
		file.Read(m_pData, m_DataSize);
		file.Close();
	}

	if(addFileParam)
	{
		CString buf;
		buf=fStatus.m_ctime.Format(_T("%d.%m.%Y  %H:%M:%S"));
		m_Parametrs.Add(new CDataSetParam(APL_T("Дата создания"), buf, m_bANSI));
		buf=fStatus.m_mtime.Format(_T("%d.%m.%Y  %H:%M:%S"));
		m_Parametrs.Add(new CDataSetParam(APL_T("Дата изменения"), buf, m_bANSI));
	}
	
	return true;
}

bool CFileDataSet::Load(CBinaryFile &file)
{
	Clear();

	UINT32 i,k;
	CDataSetParam *pParam;
	
	if(!file.Read(m_sName)) throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);
	if(!file.Read(m_sCompress_method)) throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);
	if(!file.Read(m_sCrypt_method)) throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);
	
	// Чтение параметров
	if(!file.Read(k)) throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);
	
	for(i=0;i<k;i++)
	{
		pParam = new CDataSetParam(NULL, NULL, m_bANSI);
		pParam->Load(file);
		m_Parametrs.Add(pParam);
	}

	if(m_pData)
		delete m_pData;
	m_pData = NULL;
		
	if(!file.Read(m_DataSize)) throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);

	if (m_DataSize>APL_MAX_FILE_SIZE_IN_MEMORY) 
	{
		aplGetTempFileName(_T("winetd"),_T("tmp"),m_sTempDataFile);
		if(m_sTempDataFile==_T("")) {AfxMessageBox(_T("Ошибка создания временного файла"),MB_ICONSTOP); false;}

		if(!file.WriteToFile(m_sTempDataFile,m_DataSize)){AfxMessageBox(_T("Ошибка копирования данных во временный файл."),MB_ICONSTOP); false;}
		::SetFileAttributes(m_sTempDataFile,FILE_ATTRIBUTE_READONLY);
	}
	else
	{
		m_pData = new char[m_DataSize];
		if(m_DataSize>0)
		{
			if(!file.Read(m_pData, m_DataSize))
			{
				delete m_pData;
				m_pData = NULL;
				throw(APL_LOAD_FILERDATASET_FROM_FILE_ERROR);
			}
		}
	}

	return true;
}

bool CFileDataSet::Save(CBinaryFile &file)
{
	int i;
#ifdef _UNICODE
	if (m_bANSI)
	{
		file.Write('F');
	}
	else
	{
		file.Write(L'F');
	}
#else
	file.Write('F');
#endif
	file.Write(m_sName);
	file.Write(m_sCompress_method);
	file.Write(m_sCrypt_method);
	
	// запись параметров
	file.Write((UINT32)m_Parametrs.GetSize());
	for(i=0; i<m_Parametrs.GetSize(); i++)
		m_Parametrs[i]->Save(file);
	
	file.Write(m_DataSize);
	if(0!=m_pData)file.Write(m_pData, m_DataSize);
	else if(m_sTempDataFile!=_T("")) file.WriteFromFile(m_sTempDataFile);
	
	return true;
}

void CFileDataSet::Clear()
{
	CDataSet::Clear();
	
	if(m_pData)
		delete m_pData;
	m_pData = NULL;
	m_DataSize = 0;
	if(m_sTempDataFile!=_T(""))
	{
		::SetFileAttributes(m_sTempDataFile,FILE_ATTRIBUTE_NORMAL);
		CaplFile::Remove(m_sTempDataFile);
		m_sTempDataFile=_T("");
	}
}

bool CFileDataSet::View(CString &sPathName, HANDLE &hProc)
{
	CString name;
	aplGetTempPath(name);
	name+=m_sName;
	

	if(!SaveContentToFile(name))
	{
		AfxMessageBox(APL_T("Ошибка сохранения файла"));
		return false;
	}
	
	SHELLEXECUTEINFO ExInfo;
	ExInfo.cbSize = sizeof(SHELLEXECUTEINFO);
	ExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
	ExInfo.hwnd = 0;
	ExInfo.lpVerb = _T("open");
	ExInfo.lpFile = name;
	ExInfo.lpParameters = 0;
	ExInfo.lpDirectory = 0;
	ExInfo.nShow = SW_SHOWNORMAL;
	ShellExecuteEx(&ExInfo);
	
	if((int)ExInfo.hInstApp==SE_ERR_ASSOCINCOMPLETE) 
	{
		AfxMessageBox(APL_T("Нет ассоциированного приложения"));
		return false;
	}
	if((int)ExInfo.hInstApp<=32) 
	{
		AfxMessageBox(APL_T("Ошибка запуска приложения"));
		return false;
	}

	sPathName = name;
	hProc = ExInfo.hProcess;

	return hProc!=NULL;
}

UINT64 CFileDataSet::GetBufSize(bool bUseAdditionalParam)
{
	int i;
	UINT64 size = 0;

	// так как старый вариант ЭЦП брал хеш только от тела файла
	if(bUseAdditionalParam)
	{
		size =1;//file.Write('F');
		size+=sizeof(UINT32)*3;
		size+=m_sName.GetLength()+1;//file.Write(m_sName);
		size+=m_sCompress_method.GetLength()+1;//file.Write(m_sCompress_method);
		size+=m_sCrypt_method.GetLength()+1;//file.Write(m_sCrypt_method);
		
		size+=sizeof(UINT32);//file.Write(m_Parametrs.GetSize());
		for(i=0; i<m_Parametrs.GetSize(); i++)
			size+=m_Parametrs[i]->GetBufSize();//m_Parametrs[i]->Save(file);
		
		// Чтение входящих DataSet
		size+=sizeof(UINT32);//file.Write(m_DataSize);
	}

	size+=m_DataSize;//file.Write(m_pData, m_DataSize);
	return size;
}

bool CFileDataSet::SaveToBuf(CaplSignBuf &signBuf, bool bUseAdditionalParam)
{

	int i;

	if(bUseAdditionalParam)
	{
#ifdef _UNICODE
		if (m_bANSI)
		{
			signBuf.Add('F');
		}
		else
		{
			wchar_t wc=L'F';
			signBuf.Add((BYTE*)&wc,sizeof(wchar_t));
		}
#else
		signBuf.Add('F');
#endif
		signBuf.Add(m_sName, m_bANSI); 
		signBuf.Add(m_sCompress_method, m_bANSI);
		signBuf.Add(m_sCrypt_method, m_bANSI); 

		signBuf.Add((UINT32)m_Parametrs.GetSize());
		for(i=0; i<m_Parametrs.GetSize(); i++)
			m_Parametrs[i]->SaveToBuf(signBuf);
		
		// Чтение входящих DataSet
		signBuf.Add(m_DataSize);
	}	

	if(0==m_pData)
	{
		if(m_DataSize>0 && m_sTempDataFile!=_T("")) signBuf.AddFile(m_sTempDataFile);
	}
	else signBuf.Add((BYTE*)m_pData, m_DataSize);

	return true;
}
//*************************************************************
bool CFileDataSet::LoadFromBuf(BYTE  *pBuf, int &index)
{
	int i, cnt;
	LoadStrFromBuf(m_sName, pBuf, index, m_bANSI);
	LoadStrFromBuf(m_sCompress_method, pBuf, index, m_bANSI);
	LoadStrFromBuf(m_sCrypt_method, pBuf, index, m_bANSI);
	
	CDataSetParam *pParam;
	LoadIntFromBuf(cnt, pBuf, index);
	for(i=0; i<cnt; i++)
	{
		pParam = new CDataSetParam(NULL, NULL, m_bANSI);
		pParam->LoadFromBuf(pBuf, index);
		m_Parametrs.Add(pParam);
	}
	
	// Чтение входящих DataSet
	long *pLong = (long*)&pBuf[index];
	m_DataSize = *pLong;
	index+=sizeof(long);
	char *pData = (char*)&pBuf[index];
	m_pData = new char[m_DataSize];
	memcpy(m_pData, pData, m_DataSize);
	index+=m_DataSize;
	
	return true;
}
//*************************************************************
 bool CFileDataSet::SaveFiles(LPCTSTR lpszPathName)
{
	CString sPath;
	if(lpszPathName!=0)
	{
		sPath = lpszPathName;
		if(!sPath.IsEmpty())
		{
			if(sPath.Right(1)!=_T("\\")) sPath+=_T('\\');
		}
		sPath+=m_sName;
	}
	else
	{
		TCHAR szFilter[] = _T("All Files (*.*)|*.*||");
		
		CFileDialog dlg(FALSE, NULL, m_sName, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter);
		if(dlg.DoModal()==IDOK)
		{
			sPath = dlg.GetPathName();
		}
	}
	if(!sPath.IsEmpty())
	{
		return(SaveContentToFile(sPath));
	}
	return true;
}
//*************************************************************
bool CFileDataSet::SaveContentToFile(LPCTSTR lpszPathName)
{
	if(0==lpszPathName) return false;
	if(_T('\0')==lpszPathName[0])return false;

	if(0==m_pData && m_DataSize > 0 && m_sTempDataFile!=_T(""))
	{
		long wdlg=aplStartWaitDlg( APL_T("Копирование файла..."));
		bool bCopy=CaplFile::CopyFile(m_sTempDataFile,lpszPathName,false);
		aplEndWaitDlg(wdlg);

		if(!bCopy)
		{
			AfxMessageBox(APL_T("Ошибка копирования файла из временного.\n\nВозможно, во временной папке недостаточно места."));
			return false;
		}
		::SetFileAttributes(lpszPathName,FILE_ATTRIBUTE_NORMAL);
	}
	else
	{
		CFile file;
		if(!file.Open(lpszPathName, CFile::modeCreate|CFile::modeWrite))
		{
			AfxMessageBox(APL_T("Ошибка создания файла"));
			return false;
		}
		if(m_DataSize > 0) file.Write(m_pData, m_DataSize);
		file.Close();
	}
	return true;
}
//*************************************************************