Click here to Skip to main content
15,886,026 members
Articles / Desktop Programming / MFC

The alxBase classes for work with DBF files

Rate me:
Please Sign up or sign in to vote.
5.00/5 (22 votes)
5 Nov 20021 min read 361.5K   3.8K   57  
The alxBase classes for work with dbf files.
// DBFTableDef.cpp : implementation of the CDBFTableDef class
//
/////////////////////////////////////////////////////////////////////////////
/*
�����:              �������� �.�.
����������:         alxsoft@gazinter.net
*/
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DBFTableDef.h"

#define MIN_DATE		(-657434L)  // about year 100
#define MAX_DATE		2958465L    // about year 9999

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

// ������� ������ ���������� � ����� �����
CString alxChangeFileExt(CString& strFileName, CString strNewFileExt)
{
	CString strResult;
	int i = strFileName.ReverseFind('.');
	if(i >= 0)
		strResult = strFileName.Left(i);
	return strResult += '.'+strNewFileExt;
}

// ������� ������� � ���������� ��������� �� ����� ���� �����
CMemoFile* alxNewMemoFile(UINT nMemoType)
{
	switch(nMemoType)
	{
	case MEMO_TYPE_FOXPRO:		// FoxPro
	case MEMO_TYPE_VFOXPRO:		// Visual FoxPro
	case MEMO_TYPE_FOX_DATABASE:// Visual FoxPro Database
		return new CFPTMemoFile;
	case MEMO_TYPE_SIX:			// HiPer-SIx
		return new CSMTMemoFile;
	case MEMO_TYPE_DBASEIV:		// dBASE (dBASEIV or higher)
		return new CDBTMemoFile;
	default:					// dBASE (lower dBASEIV)
		return new CMemoFile;
	}
}

// ������� ���������� ���������� ��� ����� ���� �����
LPCTSTR alxMemoFileExt(UINT nMemoType)
{
	switch(nMemoType)
	{
	case MEMO_TYPE_FOXPRO:		// .FPT - FoxPro
	case MEMO_TYPE_VFOXPRO:		// .FPT - Visual FoxPro
		return _T("FPT");
	case MEMO_TYPE_FOX_DATABASE:// .DCT - Visual FoxPro Database
		return _T("DCT");
	case MEMO_TYPE_SIX:			// .SMT - HiPer-SIx
		return _T("SMT");
	default:					// .DBT - dBASE
		return _T("DBT");
	}
}

//////////////////////////////////////////////////////////////////////////
// CDBFTableDef
IMPLEMENT_DYNAMIC(CDBFTableDef, CObject)

/* ����������� */
CDBFTableDef::CDBFTableDef()
{
	m_bOpen = FALSE;
	m_bNew = FALSE;
	m_nOpenFlag = ALX_DBF_USE_READ_ONLY | CFile::typeBinary;

	m_pMemoFile = NULL;

	m_pData = NULL;

	memset(&m_DBFHead, 0, sizeof(m_DBFHead));

	m_pOldDBFHead = NULL;
	m_pOldDBFFields = NULL;
	m_pSwapFld = NULL;
}

/* ���������� */
CDBFTableDef::~CDBFTableDef()
{
	Close();

	// ����������� ���������� �������
	if(m_pOldDBFHead != NULL)
	{
		delete[] m_pOldDBFHead;
		m_pOldDBFHead = NULL;
	}
	if(m_pOldDBFFields != NULL)
	{
		if(m_pOldDBFFields->m_pFields != NULL)
			delete[] m_pOldDBFFields->m_pFields;
		delete m_pOldDBFFields;
		m_pOldDBFFields = NULL;
	}
	if(m_pSwapFld != NULL)
	{
		delete[] m_pSwapFld;
		m_pSwapFld = NULL;
	}
}

/* ��������� ������� */
void CDBFTableDef::Open(LPCTSTR lpszName, UINT nOpenFlag)
{
	ASSERT_VALID(this);
	ASSERT(lpszName != NULL);

	// ��������� ��� �������� ����
	m_nOpenFlag = nOpenFlag | CFile::typeBinary;

	CString strMemoFileExt;
	// Re-open is invalid
	if (IsOpen())
	{
		ASSERT(FALSE);
		return;
	}

	if(m_DBFFields.m_pFields != NULL)
		delete[] m_DBFFields.m_pFields;


TRY
{

	// ��������� ����
	DBF_CHECK_ERROR(
		m_DBFile.Open(lpszName, m_nOpenFlag), ALX_DBF_ERROR_DBFILE_OPEN);
	// ������ ���������
	DBF_CHECK_ERROR(
		m_DBFile.Read(&m_DBFHead, sizeof(m_DBFHead)) == sizeof(DBF_HEAD), ALX_DBF_ERROR_DBFHEADER_READ);
	// ��������� ���������
	DBF_CHECK_ERROR(
		m_DBFHead.rec_size > 1 && m_DBFHead.last_rec >= 0, ALX_DBF_ERROR_NOT_TABLE);
	// ��������� ������ �����
	DBF_CHECK_ERROR(
		m_DBFile.GetLength() - (m_DBFHead.data_offset + m_DBFHead.rec_size * m_DBFHead.last_rec) <= 1, ALX_DBF_ERROR_NOT_TABLE);

	// ��������� ���������� �����
	if(m_DBFHead.dbf_id == 0x30) // ���� FoxPro 3.0
	{
		m_DBFFields.m_nFieldCount = (m_DBFHead.data_offset - 296)/sizeof(FIELD_REC);

		// ������ ����, ��������� ����, 1 ����
		DBF_CHECK_ERROR(
			m_DBFFields.m_nFieldCount > 0, ALX_DBF_ERROR_NOT_FIELDS);

		// ��������� ������ �����
		DBF_CHECK_ERROR(
			m_DBFile.GetLength() >= (DWORD)(m_DBFHead.data_offset + (m_DBFHead.last_rec * m_DBFHead.rec_size)),
			ALX_DBF_ERROR_FILE_SIZE);

		m_DBFFields.m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];

		// ������ ������ �����
		DBF_CHECK_ERROR(
			m_DBFile.Read((void*)m_DBFFields.m_pFields, (UINT)m_DBFFields.m_nFieldCount*sizeof(FIELD_REC)) == (UINT)m_DBFFields.m_nFieldCount*sizeof(FIELD_REC),
			ALX_DBF_ERROR_FIELDS_READ);
	}
	else
	{
		short nIndCurField = 0;
		short nFieldWidth;
		DBF_LONG lFldOffset = 1;
		BOOL bIsMoreFields = TRUE;
		short nFieldCount = (m_DBFHead.data_offset - sizeof(DBF_HEAD) - 1)/sizeof(FIELD_REC);
		FIELD_REC*	pFields = new FIELD_REC[nFieldCount];
		// ��� ������� ����
		while(bIsMoreFields && nIndCurField < nFieldCount)
		{
			// ��������� ���� ����
			if(m_DBFile.Read(&pFields[nIndCurField],sizeof(FIELD_REC)) != sizeof(FIELD_REC))
			{
				ASSERT(FALSE);
				delete[] pFields;
				ALXThrowDBFException(ALX_DBF_ERROR_FIELDS_READ);
			}
			if(bIsMoreFields)
			{
				// ��� ��������� ����
				bIsMoreFields = (pFields[nIndCurField].field_name[0] != 0x0D);
				if(bIsMoreFields)
				{
					// ���,  �������� ���� � ������
					switch(pFields[nIndCurField].field_type)
					{
					case FLD_TYPE_NUMERIC:
					case FLD_TYPE_CURRENCY:
					case FLD_TYPE_FLOAT:
					case FLD_TYPE_DOUBLE:
					case FLD_TYPE_INTEGER:
						nFieldWidth = pFields[nIndCurField].len_info.num_size.len;
						break;
					default:
						nFieldWidth = pFields[nIndCurField].len_info.char_len;
					}

					pFields[nIndCurField].field_offset = lFldOffset;
					lFldOffset = lFldOffset + nFieldWidth;
					nIndCurField++;
				}
			}
		}

		m_DBFFields.m_nFieldCount = nIndCurField;
		m_DBFFields.m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];
		memcpy(m_DBFFields.m_pFields, pFields, m_DBFFields.m_nFieldCount*sizeof(FIELD_REC));
		delete[]pFields;
	}

	UINT nMemoType = MEMO_TYPE_NOMEMO;

	// ����� �� ���� ���� ���� ?
	switch(m_DBFHead.dbf_id)
	{
	case 0x30: // Visual FoxPro 3.0
		if(m_DBFHead.table_flag & TBL_FLAG_MEMO)
			if(m_DBFHead.table_flag & TBL_FLAG_DATABASE)
				nMemoType = MEMO_TYPE_FOX_DATABASE;
			else
				nMemoType = MEMO_TYPE_VFOXPRO;
		break;
	case 0xE5:// SMT ����
		nMemoType = MEMO_TYPE_SIX;
		break;
	case 0xF5:// FPT ����
		nMemoType = MEMO_TYPE_FOXPRO;
		break;
	case 0x8B://DBT ���� dBASE IV
	case 0x7B://dBASE IV with memo 
	case 0xCB://DBT ���� dBASE IV SQL
		nMemoType = MEMO_TYPE_DBASEIV;
		break;
	case 0x83:// DBT ���� FoxBASE+/dBASE III PLUS
		nMemoType = MEMO_TYPE_DBASE;
		break;
	}

	// ���� �����, ��������� ���� ����.
	if(nMemoType)
	{
		m_pMemoFile = alxNewMemoFile(nMemoType);
		CString strMemoFileName = alxChangeFileExt(CString(lpszName), alxMemoFileExt(nMemoType));
		// ��������� ���� ����
		m_pMemoFile->Open(strMemoFileName, nOpenFlag);
	}

	m_DBFFields.m_pCurRec = new DBF_CHAR[m_DBFHead.rec_size];
	memset(m_DBFFields.m_pCurRec, 0, m_DBFHead.rec_size);

	m_bOpen = TRUE;
}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();
	Close();
}
END_CATCH

}

/* ��������� ������� */
void CDBFTableDef::Close()
{
	if(m_bOpen || m_bNew)
	{
		m_DBFile.Close();
		if(m_pMemoFile != NULL)
		{
			if(m_pMemoFile->IsOpen())
				m_pMemoFile->Close();

			switch(m_pMemoFile->GetMemoFileType())
			{
			case MEMO_TYPE_FOXPRO:
			case MEMO_TYPE_VFOXPRO:
			case MEMO_TYPE_FOX_DATABASE:
				delete (CFPTMemoFile*) m_pMemoFile;
				break;
			case MEMO_TYPE_DBASEIV:
				delete (CDBTMemoFile*) m_pMemoFile;
				break;
			case MEMO_TYPE_SIX:
				delete (CSMTMemoFile*) m_pMemoFile;
				break;
			case MEMO_TYPE_DBASE:
				delete (CMemoFile*) m_pMemoFile;
				break;
			default:
				{
					ASSERT(FALSE);
					delete m_pMemoFile;
				}
			}

			m_pMemoFile = NULL;
		}

	}

	m_bOpen = FALSE;
	m_bNew = FALSE;


	if(m_DBFFields.m_pFields != NULL)
	{
		if(m_DBFFields.m_pCurRec != NULL)
			delete[] m_DBFFields.m_pCurRec;

		delete[] m_DBFFields.m_pFields;
	}

	m_DBFFields.m_pFields = NULL;

	if(m_pData != NULL)
	{
		delete[] m_pData;
		m_pData = NULL;
	}
}

/* ������� ���������� ��� ������� */
CString CDBFTableDef::GetName()
{
	return m_DBFile.GetFileName();
}

/* ������� ���������� ������ ���� � DBF ����� */
CString CDBFTableDef::GetDBFilePath()
{
	return m_DBFile.GetFilePath();
}

/* ������� ���������� ������ ���� � Memo ����� */
CString CDBFTableDef::GetMemoFilePath()
{
	if(m_pMemoFile != NULL)
		return m_pMemoFile->GetFilePath();
	else
		return CString("");
}

/* ������� ���������� ��� ���� ����� */
CString CDBFTableDef::GetMemoName()
{
	if(m_pMemoFile != NULL)
		return m_pMemoFile->GetFileName();
	else
		return CString("");
}

/* ���� �������� ������� */
CTime CDBFTableDef::GetDateCreated()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	CFileStatus fStatus;
	m_DBFile.GetStatus(fStatus);

	return fStatus.m_ctime;
}

/* ���� ��������� ����������� ������� */
CTime CDBFTableDef::GetDateLastUpdated()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	return CTime(ALX_DBF_CENTURY + m_DBFHead.last_update[0],m_DBFHead.last_update[1],m_DBFHead.last_update[2]);
}

/* ���-�� ������� � ������� */
long CDBFTableDef::GetRecordCount()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	return m_DBFHead.last_rec;
}

/* ���-�� ����� � ������� */
short CDBFTableDef::GetFieldCount()
{
	ASSERT_VALID(this);

	return m_DBFFields.m_nFieldCount;
}

/* ������ ������ */
void CDBFTableDef::ReadRecord(long lRecNumber, void* lpBuffer)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());
	ASSERT(lpBuffer != NULL);
	ASSERT(lRecNumber < GetRecordCount());

TRY
{
	m_DBFile.Seek(m_DBFHead.data_offset + m_DBFHead.rec_size * lRecNumber, CFile::begin);
	// ������ ������
	int nRead = m_DBFile.Read(lpBuffer, m_DBFHead.rec_size);

	if(nRead != m_DBFHead.rec_size)
	{
		long lOffset = m_DBFHead.data_offset + m_DBFHead.rec_size * lRecNumber;
		if(lOffset < sizeof(DBF_HEAD) || lOffset + m_DBFHead.rec_size > (long)m_DBFile.GetLength())
			ALXThrowDBFException(ALX_DBF_ERROR_RECORD_OUTOFRANGE);
		else
			ALXThrowDBFException(ALX_DBF_ERROR_RECORD_READ);
	}
}
CATCH(CFileException, e)
{
	memset(&lpBuffer,'\0', m_DBFHead.rec_size);

	e->ReportError();
	e->Delete();

	ALXThrowDBFException(ALX_DBF_ERROR_RECORD_READ);

} END_CATCH

}

/* ���������� ������ */
void CDBFTableDef::WriteRecord(long lRecNumber, void* lpBuffer)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());
	ASSERT(lpBuffer != NULL);
	ASSERT(lRecNumber < GetRecordCount());

TRY
{
	m_DBFile.Seek(m_DBFHead.data_offset + m_DBFHead.rec_size * lRecNumber, CFile::begin);
	// ���������� ������
	m_DBFile.Write(lpBuffer, m_DBFHead.rec_size);

}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

	ALXThrowDBFException(ALX_DBF_ERROR_RECORD_WRITE);

} END_CATCH

}

/* ������ ��������� ������� */
BOOL CDBFTableDef::ReadHeader()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

TRY
{
	m_DBFile.Seek(0, CFile::begin);
	// ������ ���������
	if(m_DBFile.Read(&m_DBFHead, sizeof(m_DBFHead)) == sizeof(DBF_HEAD))
		return TRUE;
}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

	ALXThrowDBFException(ALX_DBF_ERROR_DBFHEADER_WRITE);

} END_CATCH

	return FALSE;
}

/* ���������� ��������� ������� */
void CDBFTableDef::WriteHeader()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

TRY
{
	m_DBFile.Seek(0, CFile::begin);
	// ���������� ���������
	m_DBFile.Write(&m_DBFHead, sizeof(m_DBFHead));
}
CATCH(CFileException, e)
{
	e->ReportError();
	e->Delete();

	ALXThrowDBFException(ALX_DBF_ERROR_DBFHEADER_WRITE);

} END_CATCH

}

/* ������ ���� ���� */
void CDBFTableDef::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, CString& strMemo)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	if(m_pMemoFile != NULL)
		m_pMemoFile->ReadMemoRecord(lOffsetRec, nLen, strMemo);
}

/* ������ ���� ���� */
void CDBFTableDef::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, unsigned char** pMemoData)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	if(m_pMemoFile != NULL)
		m_pMemoFile->ReadMemoRecord(lOffsetRec, nLen, pMemoData);
}

/* ���������� ���� ���� */
void CDBFTableDef::WriteMemoRecord(DBF_ULONG& lOffsetRec, DBF_LONG& nLen, CString& strMemo)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	if(m_pMemoFile != NULL)
		m_pMemoFile->WriteMemoRecord(lOffsetRec, nLen, strMemo);
}

/* ������� ���������� �������� ����*/
long CDBFTableDef::GetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, COleVariant& varValue,
						void (FAR * lpfnTextConvert) (CString& strConvertText, TextConvertDirection enDirection))
{
	// �������� �������� �� �������
	long lLen = alxGetFieldValue(pRec, pFieldRec, varValue, lpfnTextConvert);
	// ���� ����� �������� �������� �� ���� �����
	switch(pFieldRec->field_type)
	{
	case FLD_TYPE_MEMO:
		{
			if(varValue.vt == VT_UI4)
				if(varValue.ulVal > 0) // ���� ���� ������ � ���� �����
				{
					CString strValue;
					ReadMemoRecord(varValue.ulVal, lLen, strValue);

					if(lpfnTextConvert != NULL && !(pFieldRec->field_flag & FLD_FLAG_BINARY))
						(*lpfnTextConvert)(strValue, GetText);

					varValue.Clear();
					varValue = strValue;
				}
				else
				{
					lLen = 0;
					varValue.Clear();
					varValue.vt = VT_EMPTY;
				}
			else if(varValue.vt == VT_DECIMAL) // SIX
				if(varValue.decVal.Lo32 > 0) // ���� ���� ������ � ���� �����
				{
					CString strValue;
					lLen = varValue.decVal.Hi32;
					ReadMemoRecord(varValue.ulVal, lLen, strValue);
					if(lpfnTextConvert != NULL)
						(*lpfnTextConvert)(strValue, GetText);
					varValue.Clear();
					varValue = strValue;
				}
				else
				{
					lLen = 0;
					varValue.Clear();
					varValue.vt = VT_EMPTY;
				}
			break;
		}
	case FLD_TYPE_DOUBLE: // �������� FLD_TYPE_BINARY
		{
			// ���� FLD_TYPE_DOUBLE
			if(pFieldRec->len_info.num_size.len == sizeof(DBF_DOUBLE))
				break;
		}
	case FLD_TYPE_GENERAL:
	case FLD_TYPE_PICTURE:
		{
			if(m_pData != NULL)	{ delete[] m_pData;	m_pData = NULL;	}
			if(varValue.ulVal > 0) // ���� ���� ������ � ���� �����
			{
				ReadMemoRecord(varValue.ulVal, lLen, &m_pData);
				varValue.vt = VT_BYREF|VT_UI1; 
				varValue.pbVal = m_pData;
			}
			else
			{
				lLen = 0;
				varValue.Clear();
				varValue.vt = VT_EMPTY;
			}
			break;
		}
	}
	return lLen;
}

/* ������� ��������� �������� ���� */
void CDBFTableDef::SetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, const COleVariant& varValue,
						void (FAR * lpfnTextConvert) (CString& strConvertText, TextConvertDirection enDirection))
{
	// ���� ����� ���������� � ���� ����
	switch(pFieldRec->field_type)
	{
	case FLD_TYPE_MEMO:
		{
			COleVariant varDBFValue;
			if(varValue.vt == VT_BSTR)
			{
				CString strValue = varValue.bstrVal;

				DBF_CHAR*  pCurRec = new DBF_CHAR[pFieldRec->field_offset + pFieldRec->len_info.char_len];

				// �������� �������� �� �������
				alxGetFieldValue(pRec, pFieldRec, varDBFValue, NULL);

				if(varDBFValue.vt == VT_UI4)
				{
					if(lpfnTextConvert != NULL && !(pFieldRec->field_flag & FLD_FLAG_BINARY))
						(*lpfnTextConvert)(strValue, SetText);

					DBF_LONG lLen = strValue.GetLength();
					WriteMemoRecord(varDBFValue.ulVal, lLen, strValue);
				}
				else if(varDBFValue.vt == VT_DECIMAL) // SIX
				{
					if(lpfnTextConvert != NULL)
						(*lpfnTextConvert)(strValue, SetText);

					DBF_LONG lLen = varDBFValue.decVal.Hi32 > 0 ? varDBFValue.decVal.Hi32 : strValue.GetLength();
					WriteMemoRecord(varDBFValue.ulVal, lLen, strValue);
					varDBFValue.decVal.Hi32 = lLen;
				}

				delete[] pCurRec;

				alxSetFieldValue(pRec, pFieldRec, varDBFValue, NULL);
			}
			break;
		}
	case FLD_TYPE_DOUBLE: // �������� FLD_TYPE_BINARY
		{
			// ���� FLD_TYPE_DOUBLE
			if(pFieldRec->len_info.num_size.len == sizeof(DBF_DOUBLE))
			{
				alxSetFieldValue(pRec, pFieldRec, varValue, NULL);
				break;
			}
		}
	case FLD_TYPE_GENERAL:
	case FLD_TYPE_PICTURE:
		{
			break;
		}
	default:
		alxSetFieldValue(pRec, pFieldRec, varValue, lpfnTextConvert);
	}
}

#ifdef _DEBUG
void CDBFTableDef::AssertValid() const
{
	CObject::AssertValid();
}

void CDBFTableDef::Dump(CDumpContext& dc) const
{
	ASSERT_VALID(this);

	CObject::Dump(dc);

	dc << "m_bOpen = " << m_bOpen;
	dc << "\nm_bNew = " << m_bNew;

	dc << "\n";
}
#endif //_DEBUG

BOOL CDBFTableDef::IsOpen() const
{
	ASSERT_VALID(this);
	return m_bOpen || m_bNew;
}

/* ������� ����� ������� */
BOOL CDBFTableDef::CreateTable(LPCTSTR lpszName)
{
	ASSERT_VALID(this);
	ASSERT(lpszName != NULL);
	ASSERT(!IsOpen());

	m_nOpenFlag = CFile::shareExclusive | CFile::modeReadWrite | CFile::typeBinary;

	if(m_DBFFields.m_pFields != NULL)
		delete[] m_DBFFields.m_pFields;
	m_DBFFields.m_pFields = NULL;

TRY
{
	// ������� ����
	DBF_CHECK_ERROR(
		m_DBFile.Open(lpszName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive), ALX_DBF_ERROR_DBFILE_CREATE);

	COleDateTime curDate = COleDateTime::GetCurrentTime();
	memset(&m_DBFHead, 0, sizeof(DBF_HEAD));
	m_DBFHead.dbf_id = 0x03; // dBASE III // dBase IV
	m_DBFHead.last_update[0] = curDate.GetYear() - ALX_DBF_CENTURY;
	m_DBFHead.last_update[1] = curDate.GetMonth();
	m_DBFHead.last_update[2] = curDate.GetDay();
	m_DBFHead.last_rec = 0;
	m_DBFHead.data_offset = sizeof(DBF_HEAD) + 1;
	m_DBFHead.rec_size = 0;

	m_DBFFields.m_nFieldCount = 0;
	m_nEditMode = create;

	return TRUE;
}
CATCH(CFileException, e)
{

	e->ReportError();
	e->Delete();
	Close();
}
END_CATCH

	return FALSE;
}

/* ����������� ������� */
void CDBFTableDef::ModifyTable()
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	// ��������� ������� ��������� �������
	m_pOldDBFHead = new DBF_HEAD;
	memcpy(m_pOldDBFHead, &m_DBFHead, sizeof(DBF_HEAD));

	delete[] m_DBFFields.m_pCurRec;
	m_DBFFields.m_pCurRec = NULL;

	// ��������� ������� ��������� ����� �� ��������� �������
	m_pOldDBFFields = new CDBFFields;
	m_pOldDBFFields->m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];
	memcpy(m_pOldDBFFields->m_pFields, m_DBFFields.m_pFields, sizeof(FIELD_REC) * m_DBFFields.m_nFieldCount);
	m_pOldDBFFields->m_nFieldCount = m_DBFFields.m_nFieldCount;
	m_pOldDBFFields->m_pCurRec = m_DBFFields.m_pCurRec;

	// �������� ������ ��� ������ ������������ ������ � ����� �����
	m_pSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount];
	for(short i = 0; i < m_DBFFields.m_nFieldCount; i++)
		m_pSwapFld[i] = i; // ������ ������ ���� �����. ������� �������

	COleDateTime curDate = COleDateTime::GetCurrentTime();
	m_DBFHead.last_update[0] = curDate.GetYear() - ALX_DBF_CENTURY;
	m_DBFHead.last_update[1] = curDate.GetMonth();
	m_DBFHead.last_update[2] = curDate.GetDay();

	m_nEditMode = modify;

	return;
}

/* ��������� ���� � ������� */
void CDBFTableDef::AddField(FIELD_REC *pFieldRec)
{
	ASSERT(m_nEditMode != noMode);

	if(m_DBFFields.m_nFieldCount > 0)
	{
		// ��������� ������� �������� �����
		FIELD_REC*	pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];
		// �������� ������ �����
		memcpy(pFields, m_DBFFields.m_pFields, sizeof(FIELD_REC)*m_DBFFields.m_nFieldCount);
		// ����������� ������
		delete[] m_DBFFields.m_pFields;
		// ����������� �������
		m_DBFFields.m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount+1];
		// �������� ������ ����
		memcpy(m_DBFFields.m_pFields, pFields, sizeof(FIELD_REC)*m_DBFFields.m_nFieldCount);
		// �������� ����� ����
		memcpy(&m_DBFFields.m_pFields[m_DBFFields.m_nFieldCount], pFieldRec, sizeof(FIELD_REC));
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount++;
		// ����������� ��������� ������
		delete[] pFields;
		// ���� ����������� �������
		if(m_nEditMode == modify) // �������� ������ ������������ �����
		{	// �������� ��������� ������
			DBF_INT* pTmpSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount-1];
			// ��������� ������
			memcpy(pTmpSwapFld, m_pSwapFld, sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount-1));
			delete[] m_pSwapFld;
			m_pSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount];
			memcpy(m_pSwapFld, pTmpSwapFld, sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount-1));
			// ����������� �������� ������ ��������
			m_pSwapFld[m_DBFFields.m_nFieldCount-1] = -1; // ��� ���� � ������ ��������� �����. ������ ����
			delete[] pTmpSwapFld;
		}
	}
	else
	{
		// �������� ������
		m_DBFFields.m_pFields = new FIELD_REC[1];
		// �������� ����� ����
		memcpy(m_DBFFields.m_pFields, pFieldRec, sizeof(FIELD_REC));
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount = 1;
		// ���� ����������� �������
		if(m_nEditMode == modify)
		{	// �������� ������ ������������ �����
			m_pSwapFld = new DBF_INT[1];
			m_pSwapFld[0] = -1;
		}
	}
}

/* ��������� ���� � ������� */
void CDBFTableDef::InsertField(short nIndex, FIELD_REC *pFieldRec)
{
	ASSERT(m_nEditMode != noMode);
	ASSERT(nIndex < m_DBFFields.m_nFieldCount);

	if(m_DBFFields.m_nFieldCount > 0)
	{
		// ��������� ������� �������� �����
		FIELD_REC*	pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];
		// �������� ������ �����
		memcpy(pFields, m_DBFFields.m_pFields, sizeof(FIELD_REC)*m_DBFFields.m_nFieldCount);
		// ����������� ������
		delete[] m_DBFFields.m_pFields;
		// ����������� �������
		m_DBFFields.m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount+1];
		// �������� ������ ����
		memcpy(m_DBFFields.m_pFields, pFields, sizeof(FIELD_REC)*nIndex);
		memcpy(&m_DBFFields.m_pFields[nIndex+1], &pFields[nIndex], sizeof(FIELD_REC)*(m_DBFFields.m_nFieldCount-nIndex));
		// �������� ����� ����
		memcpy(&m_DBFFields.m_pFields[nIndex], pFieldRec, sizeof(FIELD_REC));
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount++;
		// ����������� ��������� ������
		delete[] pFields;
		// ���� ����������� �������
		if(m_nEditMode == modify) // �������� ������ ������������ �����
		{	// �������� ��������� ������	
			DBF_INT* pTmpSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount-1];
			// ��������� ������
			memcpy(pTmpSwapFld, m_pSwapFld, sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount-1));
			// ����������� ������
			delete[] m_pSwapFld;
			// �������� ������ ������ �������
			m_pSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount];
			// ��������������� ����������� ��������
			memcpy(m_pSwapFld, pTmpSwapFld, sizeof(DBF_INT)*nIndex);
			memcpy(&m_pSwapFld[nIndex+1], &pTmpSwapFld[nIndex], sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount-1-nIndex));
			m_pSwapFld[nIndex] = -1;
			delete[] pTmpSwapFld;
		}
	}
	else
	{
		// �������� ������
		m_DBFFields.m_pFields = new FIELD_REC[1];
		// �������� ����� ����
		memcpy(m_DBFFields.m_pFields, pFieldRec, sizeof(FIELD_REC));
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount = 1;
		// ���� ����������� �������
		if(m_nEditMode == modify)
		{	// �������� ������ ������������ �����
			m_pSwapFld = new DBF_INT[1];
			m_pSwapFld[0] = -1;
		}
	}
}

/* ������� ���� �� ������� */
void CDBFTableDef::DeleteField(short nIndex)
{
	ASSERT(m_nEditMode != noMode);
	ASSERT(nIndex < m_DBFFields.m_nFieldCount);

	if(m_DBFFields.m_nFieldCount > 1)
	{
		// ��������� ������� �������� �����
		FIELD_REC*	pFields = new FIELD_REC[m_DBFFields.m_nFieldCount];
		// �������� ������ �����
		memcpy(pFields, m_DBFFields.m_pFields, sizeof(FIELD_REC)*m_DBFFields.m_nFieldCount);
		// ����������� ������
		delete[] m_DBFFields.m_pFields;
		// �������� �������
		m_DBFFields.m_pFields = new FIELD_REC[m_DBFFields.m_nFieldCount-1];
		// �������� ������ ����
		memcpy(m_DBFFields.m_pFields, pFields, sizeof(FIELD_REC)*nIndex);
		memcpy(&m_DBFFields.m_pFields[nIndex], &pFields[nIndex+1], sizeof(FIELD_REC)*(m_DBFFields.m_nFieldCount-nIndex-1));
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount--;
		// ����������� ��������� ������
		delete[] pFields;
		// ���� ����������� �������
		if(m_nEditMode == modify) // �������� ������ ������������ �����
		{	// �������� ��������� ������	
			DBF_INT* pTmpSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount+1];
			// ��������� ������
			memcpy(pTmpSwapFld, m_pSwapFld, sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount+1));
			// ����������� ������
			delete[] m_pSwapFld;
			// �������� ������ ������ �������
			m_pSwapFld = new DBF_INT[m_DBFFields.m_nFieldCount];
			// ��������������� ����������� ��������
			memcpy(m_pSwapFld, pTmpSwapFld, sizeof(DBF_INT)*nIndex);
			memcpy(&m_pSwapFld[nIndex], &pTmpSwapFld[nIndex+1], sizeof(DBF_INT)*(m_DBFFields.m_nFieldCount+1-nIndex-1));
			delete[] pTmpSwapFld;
		}
	}
	else
	{
		// ����������� ������
		delete[] m_DBFFields.m_pFields;
		m_DBFFields.m_pFields = NULL;
		// �������� ����� ���������� �����
		m_DBFFields.m_nFieldCount = 0;
		// ���� ����������� �������
		if(m_nEditMode == modify)
		{	// �������� ������ ������������ �����
			delete[] m_pSwapFld;
			m_pSwapFld = NULL;
		}
	}
}

/* �������� ���� ������� */
void CDBFTableDef::ModifyField(short nIndex, FIELD_REC *pFieldRec)
{
	ASSERT(m_nEditMode != noMode);
	ASSERT(nIndex < m_DBFFields.m_nFieldCount);

	m_DBFFields.m_pFields[nIndex] = *pFieldRec;
}

/* ���������� ���� ������� �� ����� ������� */
void CDBFTableDef::MoveField(short nIndex, short nNewIndex)
{
	ASSERT(m_nEditMode != noMode);
	ASSERT(nIndex < m_DBFFields.m_nFieldCount);
	ASSERT(nNewIndex < m_DBFFields.m_nFieldCount);

	while(nIndex > nNewIndex)
	{
		FIELD_REC FieldRec = m_DBFFields.m_pFields[nIndex];
		m_DBFFields.m_pFields[nIndex] = m_DBFFields.m_pFields[nIndex - 1];
		m_DBFFields.m_pFields[nIndex - 1] = FieldRec;

		if(m_nEditMode == modify)
		{
			DBF_INT iSwapFld = m_pSwapFld[nIndex];
			m_pSwapFld[nIndex] = m_pSwapFld[nIndex - 1];
			m_pSwapFld[nIndex - 1] = iSwapFld;
		}

		nIndex--;
	}
	while(nIndex < nNewIndex)
	{
		FIELD_REC FieldRec = m_DBFFields.m_pFields[nIndex];
		m_DBFFields.m_pFields[nIndex] = m_DBFFields.m_pFields[nIndex + 1];
		m_DBFFields.m_pFields[nIndex + 1] = FieldRec;

		if(m_nEditMode == modify)
		{
			DBF_INT iSwapFld = m_pSwapFld[nIndex];
			m_pSwapFld[nIndex] = m_pSwapFld[nIndex + 1];
			m_pSwapFld[nIndex + 1] = iSwapFld;
		}
		nIndex++;
	}

}

/* ����� �� ��������� ��������� � ��������� ������� */
void CDBFTableDef::CancelUpdateTable()
{
	ASSERT(m_nEditMode != noMode);

	if(m_nEditMode == modify)
	{
		memcpy(&m_DBFHead, m_pOldDBFHead, sizeof(DBF_HEAD));

		memcpy(m_DBFFields.m_pFields, m_pOldDBFFields->m_pFields, sizeof(FIELD_REC) * m_pOldDBFFields->m_nFieldCount);
		m_DBFFields.m_nFieldCount = m_pOldDBFFields->m_nFieldCount;
		m_DBFFields.m_pCurRec = m_pOldDBFFields->m_pCurRec;
	}
	else
	{
		if(m_DBFile.GetLength() == 0)
		{
			CString strFilePath = m_DBFile.GetFilePath();
			m_DBFile.Close();
			::DeleteFile(strFilePath);
		}
		else
			m_DBFile.Close();
	}

	if(m_pOldDBFHead != NULL)
	{
		delete[] m_pOldDBFHead;
		m_pOldDBFHead = NULL;
	}
	if(m_pOldDBFFields != NULL)
	{
		if(m_pOldDBFFields->m_pFields != NULL)
			delete[] m_pOldDBFFields->m_pFields;
		delete m_pOldDBFFields;
		m_pOldDBFFields = NULL;
	}
	if(m_pSwapFld != NULL)
	{
		delete[] m_pSwapFld;
		m_pSwapFld = NULL;
	}

	m_DBFFields.m_pCurRec = new DBF_CHAR[m_DBFHead.rec_size];
	memset(m_DBFFields.m_pCurRec, 0, m_DBFHead.rec_size);
}

/* ��������� ��������� � ������� */
void CDBFTableDef::UpdateTable()
{
	ASSERT_VALID(this);
	ASSERT(m_nEditMode != noMode);
	ASSERT(m_DBFFields.m_nFieldCount > 0);

	BOOL bMemoExist = FALSE;
	UINT nMemoType = MEMO_TYPE_NOMEMO;

	DBF_LONG field_offset = 1;
	// ���������� ��� ����
	for(short j = 0; j < m_DBFFields.GetFieldCount(); j++)
	{
		m_DBFFields.m_pFields[j].field_offset = field_offset;
		// ��������� �������� �� ���������� ����
		switch(m_DBFFields.m_pFields[j].field_type)
		{
		case FLD_TYPE_NUMERIC:
		case FLD_TYPE_FLOAT:
			field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.num_size.len;
			break;
		case FLD_TYPE_CURRENCY:
		case FLD_TYPE_DATETIME:
		case FLD_TYPE_INTEGER:
				nMemoType = MEMO_TYPE_VFOXPRO;
				m_DBFFields.m_pFields[j].field_flag |= FLD_FLAG_BINARY;
				field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.num_size.len;
				break;
		case FLD_TYPE_DOUBLE: // or FLD_TYPE_BINARY
			if(m_DBFFields.m_pFields[j].len_info.num_size.len != sizeof(double))
			{
				nMemoType = MEMO_TYPE_DBASEIV;
				field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len;
			}
			else
			{
				nMemoType = MEMO_TYPE_VFOXPRO;
				m_DBFFields.m_pFields[j].field_flag |= FLD_FLAG_BINARY;
				field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.num_size.len;
			}
			break;
		case FLD_TYPE_MEMO:
			bMemoExist = TRUE;
			field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len;
			break;
		case FLD_TYPE_NULLFLAGS:
			m_DBFFields.m_pFields[j].field_flag |= FLD_FLAG_SYSTEM;
		case FLD_TYPE_GENERAL:
			bMemoExist = TRUE;
			nMemoType = MEMO_TYPE_VFOXPRO;
			m_DBFFields.m_pFields[j].field_flag |= FLD_FLAG_BINARY;
			field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len;
			break;
		case FLD_TYPE_PICTURE:
			bMemoExist = TRUE;
			if(nMemoType != MEMO_TYPE_VFOXPRO) nMemoType = MEMO_TYPE_FOXPRO;
			field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len;
			break;
		default:
			field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len;
		}
	}

	// ���������� ������ ������� - id � ��� ���� ���� (���� ����)
	if(nMemoType == MEMO_TYPE_VFOXPRO || m_DBFHead.dbf_id == 0x30)
	{
		m_DBFHead.dbf_id = 0x30;

		if(bMemoExist)
			m_DBFHead.table_flag |= TBL_FLAG_MEMO;

		if(m_DBFHead.table_flag & TBL_FLAG_DATABASE)
			nMemoType = MEMO_TYPE_FOX_DATABASE;
		else
			nMemoType = MEMO_TYPE_VFOXPRO;

	}
	else if(bMemoExist)
	{
		switch(m_DBFHead.dbf_id)
		{
		case 0x03: m_DBFHead.dbf_id = 0x83;	nMemoType = MEMO_TYPE_DBASE;	break;
		case 0x43: m_DBFHead.dbf_id = 0x8B; nMemoType = MEMO_TYPE_DBASEIV;	break;
		case 0x63: m_DBFHead.dbf_id = 0xCB; nMemoType = MEMO_TYPE_DBASEIV;	break;
		case 0x8B: case 0x7B: case 0xCB:	nMemoType = MEMO_TYPE_DBASEIV;	break;
		case 0xE5:							nMemoType = MEMO_TYPE_SIX;		break;
		case 0xF5:							nMemoType = MEMO_TYPE_FOXPRO;	break;
		default:
			nMemoType = MEMO_TYPE_DBASE;
		}
	}
	else
	{
		switch(m_DBFHead.dbf_id)
		{
		case 0x83: m_DBFHead.dbf_id = 0x03; break;
		case 0x8B: m_DBFHead.dbf_id = 0x43; break;
		case 0xCB: m_DBFHead.dbf_id = 0x63; break;
		}
	}

	// ��������� �������� �� ������
	m_DBFHead.data_offset = sizeof(DBF_HEAD) + sizeof(FIELD_REC) * m_DBFFields.GetFieldCount() + 1;
	if(m_DBFHead.dbf_id == 0x30)
		m_DBFHead.data_offset += 263;

	// ���������� ������ ����
	m_DBFHead.rec_size = (DBF_UINT)field_offset;

	CFile *pFileNew, *pFileOld;
	CMemoFile *pMemoFileNew = NULL, *pMemoFileOld = NULL;

	// ���� �����������
	if(m_nEditMode == modify)
	{
		// ������� ��������� ����

		pFileNew = new CFile;
		pFileOld = &m_DBFile;

		// �������� ��� ���������� �����
		CString strTmpPath, strTmpMemoPath;
		strTmpPath = alxChangeFileExt(m_DBFile.GetFilePath(), _T("_tmp"));
		strTmpMemoPath = alxChangeFileExt(m_DBFile.GetFilePath(), _T("_tmp_"));

		CFileFind mFileFind; // ������� ������ ��������� ����, ���� ����� ����
		if(mFileFind.FindFile(strTmpPath))
			CFile::Remove(strTmpPath);
		if(mFileFind.FindFile(strTmpMemoPath))
			CFile::Remove(strTmpMemoPath);

		// ������� ��������� ����
		DBF_CHECK_ERROR(
			pFileNew->Open(strTmpPath, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive), ALX_DBF_ERROR_DBFILE_CREATE);

		// ���� ���� ���� ����
		if(bMemoExist)
		{
			pMemoFileNew = alxNewMemoFile(nMemoType);
			// ������� ���� ����
			m_pMemoFile->Create(strTmpMemoPath);
		}

		pMemoFileOld = m_pMemoFile;
	}
	// ���� ������� ����� ����
	else
	{
		pFileNew = &m_DBFile;

		// ���� ���� ���� ����
		if(bMemoExist)
		{
			m_pMemoFile = alxNewMemoFile(nMemoType);
			CString strMemoFileName = alxChangeFileExt(pFileNew->GetFilePath(), alxMemoFileExt(nMemoType));
			// ������� ���� ����
			m_pMemoFile->Create(strMemoFileName);
		}
		pMemoFileNew = m_pMemoFile;
	}


	// ���������� ��������� �������
	pFileNew->Write(&m_DBFHead, sizeof(m_DBFHead));
	// ���������� ������ ����� �������
	for(j = 0; j < m_DBFFields.GetFieldCount(); j++)
		pFileNew->Write(&m_DBFFields.m_pFields[j], sizeof(FIELD_REC));
	// ������ ������������ ����� ���������� � �������
	int nEmptySpace = m_DBFHead.data_offset - (sizeof(m_DBFHead) + sizeof(FIELD_REC) * m_DBFFields.GetFieldCount());
	if(nEmptySpace > 0)
	{
		DBF_CHAR* fill = new DBF_CHAR[nEmptySpace];
		memset(fill,'\0',nEmptySpace); // ��������� ������
		fill[0] = 0x0D; // ������� ����������
		pFileNew->Write(fill, nEmptySpace); // ����������
		delete[] fill;
	}

	// ���� �����������
	if(m_nEditMode == modify)
	{
		// ��������� ������ � ����� ���������

		DBF_CHAR* pOldRec = new DBF_CHAR[m_pOldDBFHead->rec_size];
		DBF_CHAR* pNewRec = new DBF_CHAR[m_DBFHead.rec_size];
		pFileOld->Seek(m_pOldDBFHead->data_offset, CFile::begin);
		pFileNew->Seek(m_DBFHead.data_offset, CFile::begin);
		// ������� �������
		for(long i = 0; i < m_pOldDBFHead->last_rec; i++)
		{
			pFileOld->Read(pOldRec, m_pOldDBFHead->rec_size);
			pNewRec[0] = pOldRec[0];
			// ���������� ����
			for(int j = 0; j < m_DBFFields.GetFieldCount(); j++)
			{
				COleVariant varValue;
				if(m_pSwapFld[j] >= 0)
					GetFieldValue(pOldRec, m_pOldDBFFields->GetFieldRec(m_pSwapFld[j]), varValue, NULL);
				SetFieldValue(pNewRec, m_DBFFields.GetFieldRec(j), varValue, NULL);
			}
			pFileNew->Write(pNewRec, m_DBFHead.rec_size);
		}
		delete[] pOldRec;
		delete[] pNewRec;

		delete[] m_pOldDBFHead;
		m_pOldDBFHead = NULL;
		delete[] m_pOldDBFFields->m_pFields;
		delete m_pOldDBFFields;
		m_pOldDBFFields = NULL;
		delete[] m_pSwapFld;
		m_pSwapFld = NULL;
  }

	// ���������� ������� ����� 
	char eof = REC_EOF;
	pFileNew->Write(&eof, 1);

	// �������� ������ �����
	pFileNew->SetLength(m_DBFHead.data_offset + m_DBFHead.last_rec * m_DBFHead.rec_size + 1);

	// ���� �����������
	if(m_nEditMode == modify)
	{
		// ��������������� ��������� ���� � ���., � ���. � .bak

		CString strNewPath = pFileNew->GetFilePath(); 
		CString strOldPath = pFileOld->GetFilePath(); 
		CString strBakPath = alxChangeFileExt(pFileOld->GetFilePath(), _T("bak"));

		CString strNewMemoPath;
		CString strOldMemoPath;
		CString strBakMemoPath = alxChangeFileExt(pFileOld->GetFilePath(), _T("tbk"));

		if(pMemoFileNew != NULL)
		{
			strNewMemoPath = pMemoFileNew->GetFilePath();
			pMemoFileNew->Close();
		}
		if(pMemoFileOld != NULL)
		{
			strOldMemoPath = pMemoFileOld->GetFilePath();
			pMemoFileOld->Close();
			delete pMemoFileOld;
		}

		pFileOld->Close();
		pFileNew->Close();

		delete pFileNew;
		
		CFileFind mFileFind;
		if(mFileFind.FindFile(strBakPath))
			CFile::Remove(strBakPath);
		if(mFileFind.FindFile(strBakMemoPath))
			CFile::Remove(strBakMemoPath);
		CFile::Rename(strOldPath, strBakPath);
		if(!strOldMemoPath.IsEmpty())
			CFile::Rename(strOldMemoPath, strBakMemoPath);
		CFile::Rename(strNewPath, strOldPath);
		if(!strNewMemoPath.IsEmpty())
			CFile::Rename(strNewMemoPath, strOldMemoPath);

		// ��������� ����
		DBF_CHECK_ERROR(
			m_DBFile.Open(strOldPath, m_nOpenFlag), ALX_DBF_ERROR_DBFILE_OPEN);

		// ���� �����, ��������� ���� ����.
		if(nMemoType)
		{
			m_pMemoFile = pMemoFileNew;
			CString strMemoFileName = alxChangeFileExt(strOldPath, alxMemoFileExt(nMemoType));
			// ��������� ���� ����
			m_pMemoFile->Open(strMemoFileName, m_nOpenFlag);
		}

		m_bOpen = TRUE;
	}
	else
		m_bNew = TRUE;

	m_DBFFields.m_pCurRec = new DBF_CHAR[m_DBFHead.rec_size];
	memset(m_DBFFields.m_pCurRec, 0, m_DBFHead.rec_size);

	m_nEditMode = noMode;
}

/* ������� ���������� �������� ���� �� ������ ������ */
long alxGetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, COleVariant& varValue,
						void (FAR * lpfnTextConvert) (CString& strConvertText, TextConvertDirection enDirection))
{
	// Clear out variant
	varValue.Clear();
	varValue.vt = VT_EMPTY;

	long lLen;
	long nOffset = pFieldRec->field_offset;
	// � ����������� �� ���� ����
	switch(pFieldRec->field_type)
	{
	case FLD_TYPE_CHARACTER:
		{
			CString strValue;
			lLen = pFieldRec->len_info.char_len;
			// �������� ������ ��� ����
			char* buffer = strValue.GetBuffer(lLen + 1);
			// �������� ���������� ���� � �����
			memcpy(buffer, &pRec[nOffset], lLen);
			buffer[lLen] = '\0';
			strValue.ReleaseBuffer(lLen + 1);
			if(!(pFieldRec->field_flag & FLD_FLAG_BINARY))
			{
				strValue.TrimRight();
				if(lpfnTextConvert != NULL)
					(*lpfnTextConvert)(strValue, GetText);
			}
			varValue = strValue;
			break;
		}
	case FLD_TYPE_NUMERIC:
	case FLD_TYPE_FLOAT:
		{
			lLen = pFieldRec->len_info.num_size.len;
			// �������� ������ ��� ����
			char* buffer = new char[ lLen + 1 ];
			// �������� ���������� ���� � �����
			memcpy(buffer, &pRec[nOffset], lLen);
			buffer[lLen] = '\0';
			varValue.dblVal = atof(buffer);
			varValue.vt = VT_R8;
			delete[] buffer;
			break;
		}
	case FLD_TYPE_DATE:
		{
			unsigned int nYear;
			unsigned char bMonth, bDay;
			lLen = pFieldRec->len_info.char_len;
			// �������� ������ ��� ����
			char* buffer = new char[ 5 ];

			memcpy(buffer, &pRec[nOffset], 4);
			buffer[4] = '\0';
			nYear = atoi(buffer);
			memcpy(buffer, &pRec[nOffset+4], 2);
			buffer[2] = '\0';
			bMonth = atoi(buffer);
			memcpy(buffer, &pRec[nOffset+6], 2);
			buffer[2] = '\0';
			bDay = atoi(buffer);

			delete[] buffer;

			COleDateTime dteValue(nYear,bMonth,bDay,0,0,0);
			if(dteValue.GetStatus() == COleDateTime::valid)
				varValue = dteValue;
			break;
		}
	case FLD_TYPE_LOGICAL:
		{
			DBF_UCHAR chValue;
			lLen = pFieldRec->len_info.char_len;
			memcpy(&chValue, &pRec[nOffset], sizeof(DBF_UCHAR));
			if(chValue == 'T' || chValue == 't' ||chValue == 'Y' || chValue == 'y')
				varValue.boolVal = TRUE;
			else
				varValue.boolVal = FALSE;
			varValue.vt = VT_BOOL;
			break;
		}
	case FLD_TYPE_CURRENCY:
		{
			lLen = pFieldRec->len_info.num_size.len;
			memcpy(&varValue.cyVal, &pRec[nOffset], sizeof(varValue.cyVal));
			varValue.vt = VT_CY;
			break;
		}
	case FLD_TYPE_DATETIME:
		{
			COleDateTime dteValue(1,1,1,0,0,0);
			lLen = pFieldRec->len_info.char_len;
			long lDay,lHour, lMin, lSec;
			memcpy(&lDay, &pRec[nOffset], sizeof(lDay));
			memcpy(&lSec, &pRec[nOffset+4], sizeof(lSec));
			if(lDay >= 0x1A4452)
			{
				lDay = lDay - 0x1A4452;
				lSec = (lSec + 1) / 1000;
				lHour = lSec / 60 / 60;
				lSec = lSec - lHour * 60 * 60;
				lMin = lSec / 60;
				lSec = lSec - lMin * 60;

				COleDateTimeSpan dteSpan(lDay,lHour,lMin,lSec);
				dteValue = dteValue + dteSpan;
				varValue = dteValue;
			}
			break;
		}
	case FLD_TYPE_INTEGER:
		{
			lLen = pFieldRec->len_info.num_size.len;
			memcpy(&varValue.lVal, &pRec[nOffset], sizeof(varValue.lVal));
			varValue.vt = VT_I4;
			break;
		}
	case FLD_TYPE_DOUBLE: // �������� FLD_TYPE_BINARY
		{
			lLen = pFieldRec->len_info.num_size.len;
			// ���� FLD_TYPE_DOUBLE
			if(lLen == sizeof(DBF_DOUBLE))
			{
				memcpy(&varValue.dblVal, &pRec[nOffset], sizeof(varValue.dblVal));
				varValue.vt = VT_R8;
				break;
			}
		}
	case FLD_TYPE_MEMO:
		{
			lLen = pFieldRec->len_info.num_size.len;
			// ���� ����� ������� � ������� SIX (��������� ���� ���� 0x0800)
			if(lLen == 10 && pRec[nOffset] > 0x00 && pRec[nOffset] <= 0x08 && pRec[nOffset+1] == 0x00)
			{
				memcpy(&varValue.decVal.Hi32, &pRec[nOffset+2], sizeof(varValue.decVal.Hi32));
				memcpy(&varValue.decVal.Lo32, &pRec[nOffset+6], sizeof(varValue.decVal.Lo32));
				varValue.vt = VT_DECIMAL;
				break;
			}
		}
	case FLD_TYPE_GENERAL:
	case FLD_TYPE_PICTURE:
		{
			lLen = pFieldRec->len_info.num_size.len;
			if(lLen == sizeof(DBF_ULONG))
				memcpy(&varValue.ulVal, &pRec[nOffset], sizeof(varValue.ulVal));
			else if(lLen == 10)
			{
				char* buffer = new char[11];
				memcpy(buffer, &pRec[nOffset], lLen);
				buffer[lLen] = '\0';
				varValue.ulVal = atol(buffer);
				delete[] buffer;
			}
			varValue.vt = VT_UI4;
			break;
		}
	case FLD_TYPE_NULLFLAGS:
		{
			lLen = pFieldRec->len_info.num_size.len;
			varValue.ulVal = 0;
			memcpy(&varValue.ulVal, &pRec[nOffset], lLen);
			varValue.vt = VT_UI4;
			break;
		}
	default:
		{
			CString strValue;
			lLen = pFieldRec->len_info.num_size.len;
			// �������� ������ ��� ����
			char* buffer = strValue.GetBuffer(lLen + 1);
			// �������� ���������� ���� � �����
			memcpy(buffer, &pRec[nOffset], lLen);
			buffer[lLen] = '\0';
			strValue.ReleaseBuffer(lLen + 1);

			varValue = strValue;
		}
	}

	return lLen;
}

/* ������� ���������� �������� ���� � ����� ������ */
void alxSetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, const COleVariant& var,
						void (FAR * lpfnTextConvert) (CString& strConvertText, TextConvertDirection enDirection))
{
	long lLen;
	long nOffset = pFieldRec->field_offset;
	COleVariant varValue = var;
	// � ����������� �� ���� ����
	switch(pFieldRec->field_type)
	{
	case FLD_TYPE_CHARACTER:
		{
			lLen = pFieldRec->len_info.char_len;
			memset(&pRec[nOffset],' ',lLen);
			if(varValue.vt != VT_NULL)
				varValue.ChangeType(VT_BSTR);
			// � ����������� �� ���� ��������
			if(varValue.vt == VT_BSTR)
			{
				CString strValue = varValue.bstrVal;
				if(lpfnTextConvert != NULL && !(pFieldRec->field_flag & FLD_FLAG_BINARY))
					(*lpfnTextConvert)(strValue, SetText);
				strncpy(&pRec[nOffset], strValue, min(strValue.GetLength(),lLen));
			}
			break;
		}
	case FLD_TYPE_NUMERIC:
	case FLD_TYPE_FLOAT:
		{
			CString strValue,strFormat;
			lLen = pFieldRec->len_info.num_size.len;
			DBF_CHAR bDec = pFieldRec->len_info.num_size.dec;
			memset(&pRec[nOffset],' ',lLen);
			if(varValue.vt != VT_NULL)
				varValue.ChangeType(VT_R8);
			// � ����������� �� ���� ��������
			if(varValue.vt == VT_R8)
			{
				CString strFormat;
				strFormat.Format("%s.%uf","%",bDec);
				strValue.Format(strFormat,varValue.dblVal);
			}

			if(strValue.GetLength() > lLen)
			{
				if(strValue.GetAt(lLen) == '.')
					strValue = ' ' + strValue;
				strValue = strValue.Left(lLen);
			}

			strncpy(&pRec[nOffset + (lLen - strValue.GetLength())], strValue, strValue.GetLength());

			break;
		}
	case FLD_TYPE_DATE:
		{
			lLen = pFieldRec->len_info.char_len;
			COleDateTime dte;
			if(varValue.vt != VT_DATE)
				varValue.ChangeType(VT_BSTR);
			// � ����������� �� ���� ��������
			switch(varValue.vt)
			{
			case VT_BSTR:
				{
					CString strValue = varValue.bstrVal;
					if(!dte.ParseDateTime(strValue))
					{
						memset(&pRec[nOffset],' ',lLen);
						break;
					}
				}
			case VT_DATE:
				{
					memset(&pRec[nOffset],'0',lLen);
					dte.m_dt = varValue.date;
					CString strValue;
					strValue.Format("%d",dte.GetYear());
					strncpy(&pRec[nOffset + 4 - strValue.GetLength()], strValue, strValue.GetLength());
					strValue.Format("%d",dte.GetMonth());
					strncpy(&pRec[nOffset + 6 - strValue.GetLength()], strValue, strValue.GetLength());
					strValue.Format("%d",dte.GetDay());
					strncpy(&pRec[nOffset + 8 - strValue.GetLength()], strValue, strValue.GetLength());
					break;
				}
			default:
				memset(&pRec[nOffset],' ',lLen);
			}
			break;
		}
	case FLD_TYPE_DATETIME:
		{
			lLen = pFieldRec->len_info.char_len;
			COleDateTime dte;
			if(varValue.vt != VT_DATE)
				varValue.ChangeType(VT_BSTR);
			// � ����������� �� ���� ��������
			switch(varValue.vt)
			{
			case VT_BSTR:
				{
					CString strValue = varValue.bstrVal;
					if(!dte.ParseDateTime(strValue))
					{
						memset(&pRec[nOffset],' ',lLen);
						break;
					}
				 }
			case VT_DATE:
				{
					dte.m_dt = varValue.date;
					long lDay = ((long)dte.m_dt) + 0x1A4452 + 693959 - 366;
					memcpy(&pRec[nOffset], &lDay, lLen/2);
					long lSec = (dte.GetHour()* 60 * 60 + dte.GetMinute() * 60 + dte.GetSecond()) * 1000;
					memcpy(&pRec[nOffset + lLen/2], &lSec, lLen/2);
					break;
				}
			default:
				memset(&pRec[nOffset],0,lLen);
			}
			break;
		}
	case FLD_TYPE_LOGICAL:
		{
			lLen = pFieldRec->len_info.char_len;
			if(varValue.vt != VT_NULL)
				varValue.ChangeType(VT_BOOL);
			// � ����������� �� ���� ��������
			switch(varValue.vt)
			{
			case VT_BOOL:
				{
					CString strValue = varValue.boolVal == TRUE ? "T" : "F";
					strncpy(&pRec[nOffset], strValue, lLen);
					break;
				}
			default:
				memset(&pRec[nOffset],' ',lLen);
			}
			break;
		}
	case FLD_TYPE_CURRENCY:
		{
			lLen = pFieldRec->len_info.num_size.len;
			if(varValue.vt != VT_NULL)
				varValue.ChangeType(VT_CY);
			// � ����������� �� ���� ��������
			switch(varValue.vt)
			{
			case VT_CY:
				memcpy(&pRec[nOffset], &varValue.cyVal, lLen);
				break;
			default:
				memset(&pRec[nOffset],0,lLen);
			}
			break;
		}
	case FLD_TYPE_INTEGER:
		{
			// � ����������� �� ���� ��������
			lLen = pFieldRec->len_info.num_size.len;
			if(varValue.vt != VT_NULL)
				varValue.ChangeType(VT_I4);
			switch(varValue.vt)
			{
			case VT_I4:
				memcpy(&pRec[nOffset], &varValue.lVal, lLen);
				break;
			default:
				memset(&pRec[nOffset],0,lLen);
			}
			break;
		}
	case FLD_TYPE_DOUBLE: // �������� FLD_TYPE_BINARY
		{
			lLen = pFieldRec->len_info.num_size.len;
			// ���� FLD_TYPE_DOUBLE
			if(lLen == sizeof(DBF_DOUBLE))
			{
				if(varValue.vt != VT_NULL)
					varValue.ChangeType(VT_R8);
				// � ����������� �� ���� ��������
				switch(varValue.vt)
				{
				case VT_R8:
					memcpy(&pRec[nOffset], &varValue.dblVal, lLen);
					break;
				default:
					memset(&pRec[nOffset],0,lLen);
				}
			}
			break;
		}
	case FLD_TYPE_NULLFLAGS:
		{
			lLen = pFieldRec->len_info.num_size.len;
			// � ����������� �� ���� ��������
			switch(varValue.vt)
			{
			case VT_UI4:
				memcpy(&pRec[nOffset], &varValue.ulVal, lLen);
				break;
			default:
				memset(&pRec[nOffset],0,lLen);
			}
			break;
		}
	case FLD_TYPE_MEMO:
		{
			lLen = pFieldRec->len_info.num_size.len;
			if(varValue.vt == VT_UI4)
			{
				if(lLen == sizeof(DBF_ULONG))
					memcpy(&pRec[nOffset], &varValue.ulVal, lLen);
				else if(lLen == 10)
				{
					// ��������� ���������
					memset(&pRec[nOffset],' ',lLen);
					if(varValue.ulVal > 0) // ���� ������
					{
						CString strOffsetRec;
						strOffsetRec.Format("%u",varValue.ulVal);
						memcpy(&pRec[nOffset + (lLen - strOffsetRec.GetLength())], (LPCSTR)strOffsetRec, lLen);
					}

				}
			}
			else if (varValue.vt == VT_DECIMAL && lLen == 10) // SIX
			{
				if(varValue.decVal.Lo32 > 0) // ���� ������
					pRec[nOffset] = 0x08;
				else
				{
					pRec[nOffset] = 0x00;
					varValue.decVal.Hi32 = varValue.decVal.Lo32 = 0;
				}
				pRec[nOffset+1] = 0x00;
				memcpy(&pRec[nOffset+2],&varValue.decVal.Hi32, sizeof(varValue.decVal.Hi32));
				memcpy(&pRec[nOffset+6],&varValue.decVal.Lo32, sizeof(varValue.decVal.Lo32));
			}
			break;
		}
	}
}


BOOL CDBFTableDef::ChangeOpenFlag(UINT nNewFlag)
{
	ASSERT_VALID(this);
	ASSERT(IsOpen());

	// ��������� ��� �������� ����
	nNewFlag = nNewFlag | CFile::typeBinary;

	if(m_nOpenFlag == nNewFlag)
		return TRUE;

	if(m_pMemoFile != NULL && m_pMemoFile->IsOpen())
	{
		CString strMemoFileName = m_pMemoFile->GetFilePath();
		m_pMemoFile->CFile::Close();
		// ��������� ����
		if(!m_pMemoFile->CFile::Open(strMemoFileName,nNewFlag))
		{
			// ��������� ����
			DBF_CHECK_ERROR(
				m_pMemoFile->CFile::Open(strMemoFileName, m_nOpenFlag), ALX_DBF_ERROR_MEMO_OPEN);
			return FALSE;
		}
	}

	CFile* pDBFile = (CFile*) &m_DBFile;
	CString strDBFileName = pDBFile->GetFilePath();
	pDBFile->Close();
	// ��������� ����
	if(!pDBFile->Open(strDBFileName,nNewFlag))
	{
		// ��������� ����
		DBF_CHECK_ERROR(
			pDBFile->Open(strDBFileName, m_nOpenFlag), ALX_DBF_ERROR_DBFILE_OPEN);
		return FALSE;
	}

	m_nOpenFlag = nNewFlag;
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
Year of birth - 1974.
Eeducation - was ended by Kaliningrad State University in 1997.
Now I work as the engineer-programmer in Kaliningrad (RUSSIA).

Comments and Discussions