#include "stdafx.h" #include "DBTMemoFile.h" #include #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