#include "stdafx.h" #include "DBFMemCursorset.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // CDBFMemCursorset IMPLEMENT_DYNAMIC(CDBFMemCursorset, CDBFRecordset ) CDBFMemCursorset::CDBFMemCursorset(CDBFTableDef* pDBFTable) { m_bDesc = FALSE; m_bShowDeletedRec = TRUE; m_pTableData = NULL; m_pEditRec = NULL; m_lLoadRecord = 0; m_lpfnIsInclude = NULL; m_nCurCursorRecN = -1; m_bBOF = TRUE; m_bEOF = TRUE; } CDBFMemCursorset::~CDBFMemCursorset() { if (IsOpen()) Close(); } BOOL CDBFMemCursorset::Open(LPCTSTR lpszFileName, UINT nOpenFlag) { CString strFileName; if(lpszFileName == NULL) strFileName = GetDefaultDBName(); else strFileName = lpszFileName; if (strFileName.GetLength() < 4) return FALSE; // Re-Opening is invalid. if (IsOpen()) { return FALSE; } m_pTableDef = new CDBFTableDef; m_pTableDef->m_bOpen = FALSE; m_pTableDef->Open(strFileName, nOpenFlag); if(!IsOpen()) return FALSE; m_DBFFields = m_pTableDef->m_DBFFields; m_DBFHead = m_pTableDef->m_DBFHead; UINT lFileSize = (UINT)m_pTableDef->m_DBFile.GetLength(); m_pTableData = new DBF_UCHAR[lFileSize]; m_pTableDef->m_DBFile.Seek(0, CFile::begin); #if _MSC_VER > 1200 DBF_CHECK_ERROR( m_pTableDef->m_DBFile.Read(m_pTableData, lFileSize) == lFileSize, TG_DBF_ERROR_DBFILE_MEMORYLOAD); #else DBF_CHECK_ERROR( m_pTableDef->m_DBFile.ReadHuge(m_pTableData, lFileSize) == lFileSize, TG_DBF_ERROR_DBFILE_MEMORYLOAD); #endif // _MSC_VER > 1200 m_lLoadRecord = m_pTableDef->GetRecordCount(); Requery(); return TRUE; } void CDBFMemCursorset::Close() { CDBFRecordset::Close(); m_bDesc = FALSE; m_bShowDeletedRec = TRUE; m_nCurCursorRecN = -1; m_bBOF = TRUE; m_bEOF = TRUE; if(m_pTableData != NULL) { delete[] m_pTableData; m_pTableData = NULL; } m_lLoadRecord = 0; if(m_pEditRec != NULL) { delete[] m_pEditRec; m_pEditRec = NULL; } m_RecPtr.RemoveAll(); for(int i = 0; i < m_NewRecPtr.GetSize(); i++) { DBF_UCHAR* pNewRec = (DBF_UCHAR*)m_NewRecPtr[i]; delete[] pNewRec; } m_NewRecPtr.RemoveAll(); } BOOL CDBFMemCursorset::IsBOF() const { assert(IsOpen()); return (m_nCurCursorRecN == 0); } BOOL CDBFMemCursorset::IsEOF() const { assert(IsOpen()); return (m_nCurCursorRecN >= m_RecPtr.GetSize() - 1); } long CDBFMemCursorset::GetRecordCount() { assert(IsOpen()); return m_RecPtr.GetSize(); } long CDBFMemCursorset::GetAbsolutePosition() { assert(IsOpen()); return m_nCurCursorRecN; } void CDBFMemCursorset::SetAbsolutePosition(long lPosition) { assert(IsOpen()); if (lPosition<0 || lPosition>=GetRecordCount()) return; DBF_LONG lCursorRecN = lPosition; // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; m_bBOF = m_bEOF = FALSE; } void CDBFMemCursorset::MoveNext() { if (IsEOF()) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lCursorRecN = m_nCurCursorRecN; lCursorRecN++; if(lCursorRecN < GetRecordCount()) { // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; m_bBOF = m_bEOF = FALSE; } else { m_bEOF = TRUE; m_bBOF = GetRecordCount() > 0; } } void CDBFMemCursorset::MovePrev() { if (IsBOF()) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lCursorRecN = m_nCurCursorRecN; lCursorRecN--; if(lCursorRecN >= 0) { // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; m_bBOF = m_bEOF = FALSE; } else { m_bBOF = TRUE; m_bEOF = GetRecordCount() > 0; } } void CDBFMemCursorset::MoveFirst() { if (GetRecordCount() < 1) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lCursorRecN = 0; // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; m_bBOF = m_bEOF = FALSE; } void CDBFMemCursorset::MoveLast() { if (GetRecordCount() < 1) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lCursorRecN = GetRecordCount() - 1; // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; m_bBOF = m_bEOF = FALSE; } void CDBFMemCursorset::Move(long lOffsetRec) { if(!IsOpen()) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lCursorRecN = m_nCurCursorRecN + lOffsetRec; if(lOffsetRec < 0) { if(lCursorRecN < 0) { lCursorRecN = 0; m_bBOF = TRUE; } else m_bBOF = FALSE; m_bEOF = FALSE; } else if(lOffsetRec > 0) { if(lCursorRecN >= GetRecordCount()) { lCursorRecN = GetRecordCount() - 1; m_bEOF = TRUE; } else m_bEOF = FALSE; m_bBOF = FALSE; } // Call Move. m_DBFFields.m_pCurRec = GetRecord(lCursorRecN); m_nCurCursorRecN = lCursorRecN; } void CDBFMemCursorset::CancelUpdate() { assert(IsOpen()); if (m_nEditMode == DbfUtility::noMode || m_pEditRec == NULL) return; m_DBFFields.m_pCurRec = GetRecord(m_nCurCursorRecN); if(m_pEditRec != NULL) delete[] m_pEditRec; m_nEditMode = DbfUtility::noMode; } void CDBFMemCursorset::AddNew() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode || m_pEditRec != NULL) return; m_nEditMode = DbfUtility::addnew; if(m_pEditRec != NULL) delete[] m_pEditRec; m_pEditRec = new DBF_CHAR[m_DBFHead.rec_size]; memset(m_pEditRec, 0, m_DBFHead.rec_size); COleVariant varEmpty; varEmpty.Clear(); for(short i = 0; i < m_DBFFields.GetFieldCount(); i++) { FIELD_REC* pFieldRec = m_DBFFields.GetFieldRec(i); TGSetFieldValue(m_pEditRec, pFieldRec, varEmpty); } m_pEditRec[0] = REC_FLAG_NORMAL; m_DBFFields.m_pCurRec = m_pEditRec; } void CDBFMemCursorset::Edit() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode || m_nEditMode != NULL) return; m_nEditMode = DbfUtility::edit; if(m_pEditRec != NULL) delete[] m_pEditRec; m_pEditRec = new DBF_CHAR[m_DBFHead.rec_size]; memcpy(m_pEditRec, m_DBFFields.m_pCurRec, m_DBFHead.rec_size); m_DBFFields.m_pCurRec = m_pEditRec; } void CDBFMemCursorset::Update() { assert(IsOpen()); if (m_nEditMode == DbfUtility::noMode || m_pEditRec == NULL) return; switch(m_nEditMode) { case DbfUtility::edit: { SetRecord(m_nCurCursorRecN, m_pEditRec); delete [] m_pEditRec; break; } case DbfUtility::addnew: { m_DBFHead.last_rec++; m_NewRecPtr.Add(m_pEditRec); m_RecPtr.Add(m_pEditRec); m_nCurCursorRecN = max(0,GetRecordCount() - 1); SetRecord(m_nCurCursorRecN, m_pEditRec); m_bBOF = m_bEOF = FALSE; break; } } m_pEditRec = NULL; m_DBFFields.m_pCurRec = GetRecord(m_nCurCursorRecN); m_nEditMode = DbfUtility::noMode; } void CDBFMemCursorset::Delete() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return; m_DBFFields.m_pCurRec[0] = REC_FLAG_DELETED; SetRecord(m_nCurCursorRecN, m_DBFFields.m_pCurRec); } BOOL CDBFMemCursorset::IsDeleted() { assert(IsOpen()); return (m_DBFFields.m_pCurRec[0] == REC_FLAG_DELETED); } void CDBFMemCursorset::Undelete() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return; m_DBFFields.m_pCurRec[0] = REC_FLAG_NORMAL; SetRecord(m_nCurCursorRecN, m_DBFFields.m_pCurRec); } void CDBFMemCursorset::Remove() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return; m_DBFHead.last_rec--; m_RecPtr.RemoveAt(m_nCurCursorRecN); if(m_nCurCursorRecN >= GetRecordCount() && m_nCurCursorRecN > 0) m_nCurCursorRecN--; m_DBFFields.m_pCurRec = GetRecord(m_nCurCursorRecN); } BOOL CDBFMemCursorset::IsOpen() const { return (m_pTableDef == NULL ? FALSE : m_pTableDef->m_bOpen); } void CDBFMemCursorset::ThrowDBFException(long nTGDBFError) { TGThrowDBFException(nTGDBFError); } #ifdef _DEBUG void CDBFMemCursorset::AssertValid() const { CDBFRecordset::AssertValid(); } void CDBFMemCursorset::Dump(CDumpContext& dc) const { CDBFRecordset::Dump(dc); dc << "\n"; } #endif //_DEBUG DBF_CHAR* CDBFMemCursorset::GetRecord(long lRecNumber) { if (lRecNumber > m_RecPtr.GetSize()) return NULL; return (DBF_CHAR*)m_RecPtr[lRecNumber]; } void CDBFMemCursorset::GetRecord(long lRecNumber, DBF_CHAR* lpBuffer){} void CDBFMemCursorset::SetRecord(long lRecNumber, const DBF_CHAR* lpBuffer) { if (lRecNumber > m_RecPtr.GetSize()) return; memcpy(m_RecPtr[lRecNumber],lpBuffer,m_DBFHead.rec_size); } void CDBFMemCursorset::SortByField(const char* lpszName, BOOL bDesc /* = FALSE */) { for(short nIndex = 0; _stricmp(m_DBFFields.m_pFields[nIndex].field_name, lpszName) != 0 && nIndex <= m_DBFFields.m_nFieldCount; nIndex++) SortByField(nIndex, bDesc); } void CDBFMemCursorset::SortByField(int nIndex, BOOL bDesc /* = FALSE */) { m_nSortedField = nIndex; m_bDesc = bDesc; if(GetRecordCount() > 1) { FIELD_REC* pFieldRec = m_DBFFields.GetFieldRec(nIndex); switch(pFieldRec->field_type) { case FLD_TYPE_DOUBLE: if(pFieldRec->len_info.num_size.len == sizeof(DBF_DOUBLE)) break; case FLD_TYPE_GENERAL: case FLD_TYPE_PICTURE: return; } qsort( 0, m_RecPtr.GetSize() - 1 ); m_DBFFields.m_pCurRec = GetRecord(m_nCurCursorRecN); } } int CDBFMemCursorset::compare(const void *elem1, const void *elem2) { // if elem1 < elem2 return TRUE else return FALSE COleVariant var1, var2; BOOL bResult; if(m_bDesc) { m_DBFFields.m_pCurRec = (DBF_CHAR*)elem1; var2 = GetFieldValue(m_nSortedField); m_DBFFields.m_pCurRec = (DBF_CHAR*)elem2; var1 = GetFieldValue(m_nSortedField); } else { m_DBFFields.m_pCurRec = (DBF_CHAR*)elem1; var1 = GetFieldValue(m_nSortedField); m_DBFFields.m_pCurRec = (DBF_CHAR*)elem2; var2 = GetFieldValue(m_nSortedField); } if(var1 == var2) bResult = FALSE; else { if(var1.vt == VT_EMPTY && var2.vt != VT_EMPTY) bResult = TRUE; else if (var2.vt == VT_EMPTY && var1.vt != VT_EMPTY) bResult = FALSE; else { switch(var1.vt) { case VT_BSTR: { CTDbfString str1 = var1.bstrVal; CTDbfString str2 = var2.bstrVal; bResult = (str1 < str2); break; } case VT_R8: { bResult = (var1.dblVal < var2.dblVal); break; } case VT_I4: { bResult = (var1.lVal < var2.lVal); break; } case VT_CY: { COleCurrency cur1, cur2; cur1.m_cur = var1.cyVal; cur2.m_cur = var2.cyVal; bResult = (cur1 < cur2); break; } case VT_DATE: { bResult = (var1.date < var2.date); break; } case VT_BOOL: { bResult = (var1.boolVal < var2.boolVal); break; } } } } return bResult; } void CDBFMemCursorset::qsort(int from, int to) { int i, j; void *x, *tmp; // int from = 0; // int to = m_RecPtr.GetSize(); if( from >= to ) return; i = from; j = to; x = m_RecPtr[ (i+j) / 2 ]; do { while( compare(m_RecPtr[i], x) ) i++ ; // m_RecPtr[i] < x while( compare(x, m_RecPtr[j]) ) j--; // x < m_RecPtr[j] if( i <= j ) { tmp = m_RecPtr[i]; m_RecPtr[i] = m_RecPtr[j] ; m_RecPtr[j] = tmp; i++; j--; } } while( i <= j ); if( (j - from) < (to - i) ){ qsort( from, j ); qsort( i, to ); } else { qsort( i, to ); qsort( from, j ); } } void CDBFMemCursorset::SetDelete(BOOL bHideDeleteRec /* = TRUE */) { m_bShowDeletedRec = !bHideDeleteRec; } BOOL CDBFMemCursorset::GetDelete() { return !m_bShowDeletedRec; } void CDBFMemCursorset::Requery() { assert(IsOpen()); m_nEditMode = DbfUtility::noMode; m_RecPtr.SetSize(m_lLoadRecord + m_NewRecPtr.GetSize()); long nRec = 0; if(m_bShowDeletedRec) { for(long i = 0; i < m_lLoadRecord; i++) { m_RecPtr[nRec] = m_pTableData + m_DBFHead.data_offset + m_DBFHead.rec_size * i; if(m_lpfnIsInclude != NULL) { if((*m_lpfnIsInclude)((DBF_CHAR*)m_RecPtr[nRec],&m_DBFFields)) nRec++; } else nRec++; } for(long j = 0; j < m_NewRecPtr.GetSize(); j++) { m_RecPtr[nRec] = m_NewRecPtr[j]; if(m_lpfnIsInclude != NULL) { if((*m_lpfnIsInclude)((DBF_CHAR*)m_RecPtr[nRec],&m_DBFFields)) nRec++; } else nRec++; } } else { for(long i = 0; i < m_lLoadRecord; i++) { if(REC_FLAG_DELETED != *(DBF_CHAR*)(m_pTableData + m_DBFHead.data_offset + m_DBFHead.rec_size * i)) { m_RecPtr[nRec] = m_pTableData + m_DBFHead.data_offset + m_DBFHead.rec_size * i; if(m_lpfnIsInclude != NULL) { if((*m_lpfnIsInclude)((DBF_CHAR*)m_RecPtr[nRec],&m_DBFFields)) nRec++; } else nRec++; } } for(i = 0; i < m_NewRecPtr.GetSize(); i++) { if(REC_FLAG_DELETED != *(DBF_CHAR*)(m_NewRecPtr[i])) { m_RecPtr[nRec] = m_NewRecPtr[i]; if(m_lpfnIsInclude != NULL) { if((*m_lpfnIsInclude)((DBF_CHAR*)m_RecPtr[nRec],&m_DBFFields)) nRec++; } else nRec++; } } } m_RecPtr.SetSize(nRec); m_DBFHead.last_rec = m_RecPtr.GetSize(); if(GetRecordCount() > 0) MoveFirst(); else m_nCurCursorRecN = 0; } BOOL CDBFMemCursorset::Save() { CFile* pDBFile = &m_pTableDef->m_DBFile; /* if (!SaveFile.Open(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyNone)) { // ReportSaveLoadException(lpszPathName, &fe, // TRUE, AFX_IDP_INVALID_FILENAME); return FALSE; } */ DBF_CHAR* pRec; pDBFile->Seek(m_DBFHead.data_offset, CFile::begin); for(long i = 0; i < m_lLoadRecord; i++) { pRec = (DBF_CHAR*)(m_pTableData + m_DBFHead.data_offset + m_DBFHead.rec_size * i); pDBFile->Write(pRec, m_DBFHead.rec_size); } for(long j = 0; j < m_NewRecPtr.GetSize(); j++) { pRec = (DBF_CHAR*) m_NewRecPtr[j]; pDBFile->Write(pRec, m_DBFHead.rec_size); } char eof = REC_EOF; pDBFile->Write(&eof, 1); COleDateTime curDate = COleDateTime::GetCurrentTime(); if(m_DBFHead.dbf_id == 0x30) // Visual FoxPro { #if ADS == 15 m_DBFHead.last_update[0] = atof(curDate.Format(_T("%y"))); #else m_DBFHead.last_update[0] = _tstoi(curDate.Format(_T("%y"))); #endif } else m_DBFHead.last_update[0] = curDate.GetYear() - TG_DBF_CENTURY; m_DBFHead.last_update[1] = curDate.GetMonth(); m_DBFHead.last_update[2] = curDate.GetDay(); m_DBFHead.last_rec = i + j; pDBFile->Seek(0, CFile::begin); pDBFile->Write(&m_DBFHead, sizeof(DBF_HEAD)); for(i = 0; i < m_DBFFields.GetFieldCount(); i++) pDBFile->Write(m_DBFFields.GetFieldRec(i), sizeof(FIELD_REC)); char end = 0x0D; pDBFile->Write(&end, 1); pDBFile->SetLength(m_DBFHead.data_offset + m_DBFHead.last_rec * m_DBFHead.rec_size + 1); m_pTableDef->m_DBFHead.last_rec = m_DBFHead.last_rec; return TRUE; } void CDBFMemCursorset::SetFilter(BOOL (FAR * lpfnIsInclude) (DBF_CHAR*, CDBFFields* pDBFFields)) { m_lpfnIsInclude = lpfnIsInclude; }