594 lines
10 KiB
C++
594 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "DBTMemoFile.h"
|
|
#include <math.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
// CDBTMemoFile
|
|
IMPLEMENT_DYNAMIC(CDBTMemoFile, CMemoFile)
|
|
|
|
CDBTMemoFile::CDBTMemoFile()
|
|
{
|
|
|
|
}
|
|
|
|
CDBTMemoFile::~CDBTMemoFile()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
BOOL CDBTMemoFile::Open(LPCTSTR lpszName, UINT nOpenFlag)
|
|
{
|
|
if (!lpszName)
|
|
return FALSE;
|
|
nOpenFlag = nOpenFlag | CFile::typeBinary;
|
|
|
|
// Re-open is invalid
|
|
if (IsOpen())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// TRY
|
|
// {
|
|
DBF_CHECK_ERROR(
|
|
CFile::Open(lpszName, nOpenFlag), TG_DBF_ERROR_MEMO_OPEN);
|
|
|
|
DBF_CHECK_ERROR(
|
|
ReadHeader(),TG_DBF_ERROR_MEMO_HEAD_READ);
|
|
|
|
DBF_CHECK_ERROR(m_DBTHead.block_size > 0,TG_DBF_ERROR_MEMO_BLOCK_SIZE);
|
|
|
|
m_bOpen = TRUE;
|
|
// }
|
|
// CATCH(CFileException, e)
|
|
// {
|
|
// e->ReportError();
|
|
// e->Delete();
|
|
// Close();
|
|
// }
|
|
// END_CATCH
|
|
return TRUE;
|
|
}
|
|
|
|
void CDBTMemoFile::Close()
|
|
{
|
|
if(m_bOpen)
|
|
CMemoFile::Close();
|
|
}
|
|
|
|
UINT CDBTMemoFile::GetMemoFileType()
|
|
{
|
|
return MEMO_TYPE_DBASEIV;
|
|
}
|
|
|
|
BOOL CDBTMemoFile::ReadHeader()
|
|
{
|
|
if (!m_hFile)
|
|
return FALSE;
|
|
TRY
|
|
{
|
|
Seek(0, CFile::begin);
|
|
|
|
if(Read(&m_DBTHead, sizeof(DBT_HEAD)) != sizeof(DBT_HEAD))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
CATCH(CFileException, e)
|
|
{
|
|
e->ReportError();
|
|
e->Delete();
|
|
|
|
} END_CATCH
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CDBTMemoFile::WriteHeader()
|
|
{
|
|
if (!m_hFile)
|
|
return FALSE;
|
|
TRY
|
|
{
|
|
Seek(0, CFile::begin);
|
|
|
|
Write(&m_DBTHead, sizeof(DBT_HEAD));
|
|
|
|
return TRUE;
|
|
}
|
|
CATCH(CFileException, e)
|
|
{
|
|
e->ReportError();
|
|
e->Delete();
|
|
|
|
} END_CATCH
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CDBTMemoFile::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo)
|
|
{
|
|
if (lOffsetRec < 0)
|
|
return FALSE;
|
|
|
|
strMemo = "";
|
|
|
|
if(!IsOpen())
|
|
return FALSE;
|
|
|
|
// TRY
|
|
// {
|
|
DBF_LONG nLenMemo = 0;
|
|
|
|
Seek(lOffsetRec * m_DBTHead.block_size + sizeof(DBF_LONG),CFile::begin);
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
nLenMemo -= sizeof(DBF_LONG) * 2;
|
|
|
|
|
|
DBF_CHECK_ERROR(nLenMemo > 0,TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
char* buffer = new char[nLenMemo+1] /*strMemo.GetBuffer(nLenMemo + 1)*/;
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(buffer, nLenMemo) == (UINT)nLenMemo,
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
buffer[nLenMemo] = '\0';
|
|
// strMemo.ReleaseBuffer(nLenMemo + 1);
|
|
strMemo = buffer;
|
|
delete [] buffer;
|
|
buffer = NULL;
|
|
|
|
nLen = nLenMemo;
|
|
|
|
// }
|
|
// CATCH(CFileException, e)
|
|
// {
|
|
// e->ReportError();
|
|
// e->Delete();
|
|
//
|
|
// TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
//
|
|
// } END_CATCH
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CDBTMemoFile::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, unsigned char** pMemoData)
|
|
{
|
|
assert(IsOpen());
|
|
if (lOffsetRec < 0)
|
|
return FALSE;
|
|
|
|
*pMemoData = NULL;
|
|
|
|
if(!IsOpen())
|
|
return FALSE;
|
|
|
|
// TRY
|
|
// {
|
|
DBF_LONG nLenMemo = 0;
|
|
|
|
Seek(lOffsetRec * m_DBTHead.block_size + sizeof(DBF_LONG),CFile::begin);
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
nLenMemo -= sizeof(DBF_LONG) * 2;
|
|
|
|
|
|
DBF_CHECK_ERROR(nLenMemo > 0,TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
*pMemoData = new unsigned char[nLenMemo];
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(*pMemoData, nLenMemo) == (UINT)nLenMemo,
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
nLen = nLenMemo;
|
|
|
|
// }
|
|
// CATCH(CFileException, e)
|
|
// {
|
|
// e->ReportError();
|
|
// e->Delete();
|
|
//
|
|
// TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
//
|
|
// } END_CATCH
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CDBTMemoFile::WriteMemoRecord(DBF_ULONG& lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo)
|
|
{
|
|
|
|
|
|
if(!IsOpen())
|
|
return FALSE;
|
|
|
|
// TRY
|
|
// {
|
|
DBF_LONG nLenMemo = 0;
|
|
|
|
|
|
if(lOffsetRec > 0)
|
|
{
|
|
|
|
DBF_UINT nNeedBlockCnt = (DBF_UINT) ceil(((double)(strMemo.GetLength() + sizeof(DBF_ULONG) + sizeof(DBF_LONG)))/((double)m_DBTHead.block_size));
|
|
|
|
if(strMemo.IsEmpty())
|
|
{
|
|
|
|
DeleteMemoRecord(lOffsetRec);
|
|
lOffsetRec = 0;
|
|
}
|
|
else
|
|
{
|
|
Seek(lOffsetRec * m_DBTHead.block_size + sizeof(DBF_LONG),CFile::begin);
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
DBF_UINT nBlockCnt = (DBF_UINT) ceil(((double)(nLenMemo))/((double)m_DBTHead.block_size));
|
|
|
|
|
|
if(nBlockCnt != nNeedBlockCnt)
|
|
{
|
|
|
|
DeleteMemoRecord(lOffsetRec);
|
|
lOffsetRec = 0;
|
|
|
|
|
|
if(!UndeleteMemoRecord(lOffsetRec, strMemo))
|
|
lOffsetRec = AddMemoRecord(strMemo);
|
|
}
|
|
else
|
|
|
|
UpdateMemoRecord(lOffsetRec, strMemo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if(!UndeleteMemoRecord(lOffsetRec, strMemo))
|
|
|
|
lOffsetRec = AddMemoRecord(strMemo);
|
|
}
|
|
// }
|
|
// CATCH(CFileException, e)
|
|
// {
|
|
// e->ReportError();
|
|
// e->Delete();
|
|
//
|
|
// TGThrowDBFException(TG_DBF_ERROR_MEMO_FIELD_WRITE);
|
|
//
|
|
// } END_CATCH
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DBF_LONG CDBTMemoFile::AddMemoRecord(CTDbfString& strMemo)
|
|
{
|
|
|
|
DBF_ULONG lOffsetRec = 0;
|
|
|
|
TRY
|
|
{
|
|
|
|
DBF_LONG nSign = MF_USEDREC;
|
|
DBF_LONG nLenMemo = strMemo.GetLength() + sizeof(DBF_LONG) * 2;
|
|
|
|
lOffsetRec = (DBF_ULONG) ceil((double)GetLength() / (double)m_DBTHead.block_size);
|
|
|
|
Seek(lOffsetRec * m_DBTHead.block_size,CFile::begin);
|
|
|
|
|
|
Write(&nSign, sizeof(nSign));
|
|
|
|
|
|
Write(&nLenMemo, sizeof(nLenMemo));
|
|
|
|
|
|
Write(strMemo.toLPCSTR(), strMemo.GetLength());
|
|
|
|
ReadHeader();
|
|
|
|
if(m_DBTHead.next_block == lOffsetRec)
|
|
{
|
|
m_DBTHead.next_block = (DBF_ULONG) ceil((double)GetLength() / (double)m_DBTHead.block_size);
|
|
WriteHeader();
|
|
}
|
|
|
|
|
|
SetLength((DBF_ULONG) ceil((double)GetLength() / (double)m_DBTHead.block_size) * m_DBTHead.block_size);
|
|
}
|
|
CATCH(CFileException, e)
|
|
{
|
|
e->ReportError();
|
|
e->Delete();
|
|
|
|
} END_CATCH
|
|
|
|
return lOffsetRec;
|
|
}
|
|
|
|
|
|
void CDBTMemoFile::UpdateMemoRecord(DBF_ULONG lOffsetRec, CTDbfString& strMemo)
|
|
{
|
|
|
|
TRY
|
|
{
|
|
|
|
DBF_LONG nLenMemo = strMemo.GetLength() + sizeof(DBF_LONG) * 2;
|
|
|
|
Seek(lOffsetRec * m_DBTHead.block_size + sizeof(DBF_LONG),CFile::begin);
|
|
|
|
Write(&nLenMemo, sizeof(nLenMemo));
|
|
|
|
|
|
Write(strMemo.toLPCSTR(), strMemo.GetLength());
|
|
|
|
}
|
|
CATCH(CFileException, e)
|
|
{
|
|
e->ReportError();
|
|
e->Delete();
|
|
|
|
} END_CATCH
|
|
|
|
}
|
|
|
|
|
|
BOOL CDBTMemoFile::DeleteMemoRecord(DBF_ULONG lDelRec)
|
|
{
|
|
|
|
// TRY
|
|
// {
|
|
DBF_LONG nLenMemo = 0;
|
|
|
|
DBF_UINT nBlockSize = m_DBTHead.block_size;
|
|
|
|
Seek(lDelRec * nBlockSize + sizeof(DBF_ULONG),CFile::begin);
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nLenMemo, sizeof(nLenMemo)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
DBF_LONG nDelBlockCnt = (DBF_LONG) ceil(((double)nLenMemo)/((double)nBlockSize));
|
|
|
|
ReadHeader();
|
|
|
|
|
|
DBF_ULONG lPrevFreeRec = 0;
|
|
|
|
DBF_ULONG lCurFreeRec = 0;
|
|
|
|
DBF_ULONG lNextFreeRec = m_DBTHead.next_block;
|
|
|
|
DBF_ULONG lEOFRec = (DBF_ULONG) ceil((double)GetLength() / (double)nBlockSize);
|
|
|
|
|
|
while(lNextFreeRec != lEOFRec && lNextFreeRec != MF_USEDREC)
|
|
{
|
|
DBF_LONG nCurFreeBlockCnt = 1;
|
|
|
|
lPrevFreeRec = lCurFreeRec;
|
|
lCurFreeRec = lNextFreeRec;
|
|
|
|
Seek(lCurFreeRec * nBlockSize,CFile::begin);
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&lNextFreeRec, sizeof(lNextFreeRec)) == sizeof(DBF_ULONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nCurFreeBlockCnt, sizeof(nCurFreeBlockCnt)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
if(lCurFreeRec + nCurFreeBlockCnt == lDelRec)
|
|
{
|
|
Seek(lCurFreeRec * nBlockSize + sizeof(DBF_LONG),CFile::begin);
|
|
|
|
|
|
nCurFreeBlockCnt += nDelBlockCnt;
|
|
Write(&nCurFreeBlockCnt, sizeof(nCurFreeBlockCnt));
|
|
|
|
return FALSE;
|
|
}
|
|
else if(lDelRec + nDelBlockCnt == lCurFreeRec)
|
|
{
|
|
Seek(lDelRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
Write(&lNextFreeRec, sizeof(lNextFreeRec));
|
|
|
|
nDelBlockCnt += nCurFreeBlockCnt;
|
|
Write(&nDelBlockCnt, sizeof(nDelBlockCnt));
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
if(lPrevFreeRec > 0)
|
|
{
|
|
Seek(lPrevFreeRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
Write(&lDelRec, sizeof(lDelRec));
|
|
|
|
}
|
|
else
|
|
{
|
|
m_DBTHead.next_block = lDelRec;
|
|
|
|
WriteHeader();
|
|
}
|
|
|
|
Seek(lDelRec * nBlockSize,CFile::begin);
|
|
|
|
Write(&lEOFRec, sizeof(lEOFRec));
|
|
|
|
Write(&nDelBlockCnt, sizeof(nDelBlockCnt));
|
|
|
|
// }
|
|
// CATCH(CFileException, e)
|
|
// {
|
|
// e->ReportError();
|
|
// e->Delete();
|
|
//
|
|
// } END_CATCH
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CDBTMemoFile::UndeleteMemoRecord(DBF_ULONG& lOffsetRec, CTDbfString& strMemo)
|
|
{
|
|
|
|
TRY
|
|
{
|
|
DBF_LONG nLenData = strMemo.GetLength();
|
|
|
|
DBF_LONG nLenMemo = nLenData + sizeof(DBF_LONG) * 2;
|
|
|
|
DBF_UINT nBlockSize = m_DBTHead.block_size;
|
|
|
|
DBF_LONG nNeedBlockCnt = (DBF_LONG) ceil(((double)(nLenMemo))/((double)nBlockSize));
|
|
|
|
ReadHeader();
|
|
|
|
|
|
DBF_ULONG lPrevFreeRec = 0;
|
|
|
|
DBF_ULONG lCurFreeRec = 0;
|
|
|
|
DBF_ULONG lNextFreeRec = m_DBTHead.next_block;
|
|
|
|
DBF_ULONG lEOFRec = (DBF_ULONG) ceil((double)GetLength() / (double)nBlockSize);
|
|
|
|
|
|
while(lNextFreeRec != lEOFRec && lNextFreeRec != MF_USEDREC)
|
|
{
|
|
DBF_LONG nCurFreeBlockCnt = 1;
|
|
|
|
lPrevFreeRec = lCurFreeRec;
|
|
lCurFreeRec = lNextFreeRec;
|
|
|
|
Seek(lCurFreeRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&lNextFreeRec, sizeof(lNextFreeRec)) == sizeof(DBF_ULONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
DBF_CHECK_ERROR(
|
|
Read(&nCurFreeBlockCnt, sizeof(nCurFreeBlockCnt)) == sizeof(DBF_LONG),
|
|
TG_DBF_ERROR_MEMO_FIELD_READ);
|
|
|
|
|
|
if(nNeedBlockCnt < nCurFreeBlockCnt)
|
|
{
|
|
lOffsetRec = (lCurFreeRec + nCurFreeBlockCnt - nNeedBlockCnt);
|
|
|
|
Seek(lOffsetRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
DBF_LONG nSign = MF_USEDREC;
|
|
|
|
|
|
Write(&nSign, sizeof(nSign));
|
|
|
|
|
|
Write(&nLenMemo, sizeof(nLenMemo));
|
|
|
|
|
|
Write(strMemo.toLPCSTR(), strMemo.GetLength());
|
|
|
|
Seek(lCurFreeRec * nBlockSize + sizeof(DBF_ULONG),CFile::begin);
|
|
|
|
|
|
nCurFreeBlockCnt -= nNeedBlockCnt;
|
|
Write(&nCurFreeBlockCnt, sizeof(nCurFreeBlockCnt));
|
|
|
|
return TRUE;
|
|
}
|
|
else if(nNeedBlockCnt == nCurFreeBlockCnt)
|
|
{
|
|
lOffsetRec = lCurFreeRec;
|
|
|
|
Seek(lOffsetRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
DBF_LONG nSign = MF_USEDREC;
|
|
|
|
|
|
Write(&nSign, sizeof(nSign));
|
|
|
|
|
|
Write(&nLenMemo, sizeof(nLenMemo));
|
|
|
|
|
|
Write(strMemo.toLPCSTR(), strMemo.GetLength());
|
|
|
|
Seek(lPrevFreeRec * nBlockSize,CFile::begin);
|
|
|
|
|
|
Write(&lNextFreeRec, sizeof(lNextFreeRec));
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
CATCH(CFileException, e)
|
|
{
|
|
e->ReportError();
|
|
e->Delete();
|
|
|
|
} END_CATCH
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
void CDBTMemoFile::AssertValid() const
|
|
{
|
|
CMemoFile::AssertValid();
|
|
}
|
|
|
|
void CDBTMemoFile::Dump(CDumpContext& dc) const
|
|
{
|
|
|
|
|
|
CMemoFile::Dump(dc);
|
|
|
|
dc << "m_DBTHead.next_block = " << m_DBTHead.next_block;
|
|
dc << "m_DBTHead.dbf_file_name = " << m_DBTHead.dbf_file_name;
|
|
dc << "m_DBTHead.block_size = " << m_DBTHead.block_size;
|
|
|
|
dc << "\n";
|
|
}
|
|
#endif //_DEBUG
|