#include "stdafx.h" #include "DBFTableDef.h" #define MIN_DATE (-657434L) // about year 100 #define MAX_DATE 2958465L // about year 9999 // CDBFTableDef IMPLEMENT_DYNAMIC(CDBFTableDef, CObject) CDBFTableDef::CDBFTableDef() { m_bOpen = FALSE; m_bNew = FALSE; m_nOpenFlag = TG_DBF_USE_READ_ONLY | CFile::typeBinary; m_pMemoFile = 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; } } BOOL CDBFTableDef::Open(LPCTSTR lpszName, UINT nOpenFlag) { if (!lpszName) return FALSE; m_nOpenFlag = nOpenFlag | CFile::typeBinary; CTDbfString strMemoFileExt; if (IsOpen()) { return FALSE; } if(m_DBFFields.m_pFields != NULL) delete[] m_DBFFields.m_pFields; // TRY // { DBF_CHECK_ERROR( m_DBFile.Open(lpszName, m_nOpenFlag), TG_DBF_ERROR_DBFILE_OPEN); DBF_CHECK_ERROR( m_DBFile.Read(&m_DBFHead, sizeof(m_DBFHead)) == sizeof(DBF_HEAD), TG_DBF_ERROR_DBFHEADER_READ); DBF_CHECK_ERROR( m_DBFHead.rec_size > 1 && m_DBFHead.last_rec >= 0, TG_DBF_ERROR_NOT_TABLE); DBF_CHECK_ERROR( m_DBFile.GetLength() - (m_DBFHead.data_offset + m_DBFHead.rec_size * m_DBFHead.last_rec) <= 1, TG_DBF_ERROR_NOT_TABLE); if(m_DBFHead.dbf_id == 0x30) { m_DBFFields.m_nFieldCount = (m_DBFHead.data_offset - 296)/sizeof(FIELD_REC); DBF_CHECK_ERROR( m_DBFFields.m_nFieldCount > 0, TG_DBF_ERROR_NOT_FIELDS); DBF_CHECK_ERROR( m_DBFile.GetLength() >= (DWORD)(m_DBFHead.data_offset + (m_DBFHead.last_rec * m_DBFHead.rec_size)), TG_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), TG_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)) { delete[] pFields; TGThrowDBFException(TG_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 = 0; switch(m_DBFHead.dbf_id) { case 0x30: // Visual FoxPro 3.0 { if(m_DBFHead.table_flag & 0x02) { CString strFileExt = lpszName; strFileExt = strFileExt.Right(strFileExt.GetLength() - strFileExt.ReverseFind('.')); strFileExt.MakeUpper(); if(strFileExt == _T(".DBC")) nMemoType = MEMO_TYPE_FOX_DATABASE; else nMemoType = MEMO_TYPE_FOXPRO; m_pMemoFile = new CFPTMemoFile; } break; } case 0xE5:// SMT { nMemoType = MEMO_TYPE_SIX; m_pMemoFile = new CSMTMemoFile; break; } case 0xF5:// FPT { nMemoType = MEMO_TYPE_FOXPRO; m_pMemoFile = new CFPTMemoFile; break; } case 0x8B://DBT dBASE IV case 0x7B://dBASE IV with memo case 0xCB://DBT dBASE IV SQL { nMemoType = MEMO_TYPE_DBASEIV; m_pMemoFile = new CDBTMemoFile; break; } case 0x83:// DBT FoxBASE+/dBASE III PLUS { nMemoType = MEMO_TYPE_DBASE; m_pMemoFile = new CMemoFile; break; } } if(nMemoType) { CString strMemoFileName = lpszName; CString strMemoFileExt = lpszName; switch(nMemoType) { case MEMO_TYPE_FOXPRO: strMemoFileExt = _T(".FPT"); break; case MEMO_TYPE_FOX_DATABASE: strMemoFileExt = _T(".DCT"); break; case MEMO_TYPE_SIX: strMemoFileExt = _T(".SMT"); break; default: strMemoFileExt = _T(".DBT"); } strMemoFileName = strMemoFileName.Left(strMemoFileName.ReverseFind('.')) + strMemoFileExt; 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 return TRUE; } 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_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: { 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; } CTDbfString CDBFTableDef::GetName() { return m_DBFile.GetFileName(); } CTDbfString CDBFTableDef::GetDBFilePath() { return m_DBFile.GetFilePath(); } CTime CDBFTableDef::GetDateCreated() { assert(IsOpen()); CFileStatus fStatus; m_DBFile.GetStatus(fStatus); return fStatus.m_ctime; } CTime CDBFTableDef::GetDateLastUpdated() { assert(IsOpen()); return CTime(TG_DBF_CENTURY + m_DBFHead.last_update[0],m_DBFHead.last_update[1],m_DBFHead.last_update[2]); } long CDBFTableDef::GetRecordCount() { assert(IsOpen()); return m_DBFHead.last_rec; } short CDBFTableDef::GetFieldCount() { return m_DBFFields.m_nFieldCount; } void CDBFTableDef::ReadRecord(LONG_PTR lRecNumber, void* lpBuffer) { assert(IsOpen()); if (!lpBuffer || lRecNumber > GetRecordCount()) return; 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_PTR lOffset = m_DBFHead.data_offset + m_DBFHead.rec_size * lRecNumber; if(lOffset < sizeof(DBF_HEAD) || lOffset + m_DBFHead.rec_size > (LONG_PTR)m_DBFile.GetLength()) TGThrowDBFException(TG_DBF_ERROR_RECORD_OUTOFRANGE); else TGThrowDBFException(TG_DBF_ERROR_RECORD_READ); } } CATCH(CFileException, e) { memset(&lpBuffer,'\0', m_DBFHead.rec_size); e->ReportError(); e->Delete(); TGThrowDBFException(TG_DBF_ERROR_RECORD_READ); } END_CATCH } void CDBFTableDef::WriteRecord(long lRecNumber, void* lpBuffer) { assert(IsOpen()); if (!lpBuffer || lRecNumber > GetRecordCount()) return; 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(); TGThrowDBFException(TG_DBF_ERROR_RECORD_WRITE); } END_CATCH } BOOL CDBFTableDef::ReadHeader() { 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(); TGThrowDBFException(TG_DBF_ERROR_DBFHEADER_WRITE); } END_CATCH return FALSE; } void CDBFTableDef::WriteHeader() { assert(IsOpen()); TRY { m_DBFile.Seek(0, CFile::begin); m_DBFile.Write(&m_DBFHead, sizeof(m_DBFHead)); } CATCH(CFileException, e) { e->ReportError(); e->Delete(); TGThrowDBFException(TG_DBF_ERROR_DBFHEADER_WRITE); } END_CATCH } void CDBFTableDef::ReadMemoRecord(DBF_ULONG lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo) { 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(IsOpen()); if(m_pMemoFile != NULL) m_pMemoFile->ReadMemoRecord(lOffsetRec, nLen, pMemoData); } void CDBFTableDef::WriteMemoRecord(DBF_ULONG& lOffsetRec, DBF_LONG& nLen, CTDbfString& strMemo) { assert(IsOpen()); if(m_pMemoFile != NULL) m_pMemoFile->WriteMemoRecord(lOffsetRec, nLen, strMemo); } #ifdef _DEBUG void CDBFTableDef::AssertValid() const { CObject::AssertValid(); } void CDBFTableDef::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "m_bOpen = " << m_bOpen; dc << "\nm_bNew = " << m_bNew; dc << "\n"; } #endif //_DEBUG // CDBFTableDef inlines inline BOOL CDBFTableDef::IsOpen() const { return m_bOpen; } void CDBFTableDef::AddField(FIELD_REC *pFieldRec) { if (m_nEditMode == noMode) return; 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) { if (m_nEditMode == noMode || nIndex > m_DBFFields.m_nFieldCount) return; 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) { if (m_nEditMode == noMode || nIndex > m_DBFFields.m_nFieldCount) return; 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; } } } BOOL CDBFTableDef::UpdateTable() { if (m_nEditMode == noMode || m_DBFFields.m_nFieldCount < 0) return FALSE; 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: case FLD_TYPE_CURRENCY: case FLD_TYPE_DATETIME: case FLD_TYPE_INTEGER: case FLD_TYPE_DOUBLE: field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.num_size.len; break; default: field_offset = field_offset + m_DBFFields.m_pFields[j].len_info.char_len; } } 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; if(m_nEditMode == modify) { pFileNew = new CFile; pFileOld = &m_DBFile; CString strTmpPath; strTmpPath = m_DBFile.GetFilePath(); int i = strTmpPath.ReverseFind('.'); if(i >= 0) strTmpPath = strTmpPath.Left(i); strTmpPath = strTmpPath + _T("._tmp"); CFileFind mFileFind; if(mFileFind.FindFile(strTmpPath)) CFile::Remove(strTmpPath); DBF_CHECK_ERROR( pFileNew->Open(strTmpPath, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive), TG_DBF_ERROR_DBFILE_CREATE); } else pFileNew = &m_DBFile; 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); memset(pNewRec, ' ', m_DBFHead.rec_size); pNewRec[0] = pOldRec[0]; for(int j = 0; j < m_DBFFields.GetFieldCount(); j++) { COleVariant varValue; if(m_pSwapFld[j] >= 0) TGGetFieldValue(pOldRec, m_pOldDBFFields->GetFieldRec(m_pSwapFld[j]), varValue); TGSetFieldValue(pNewRec, m_DBFFields.GetFieldRec(j), varValue); } 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) { CString strNewPath = pFileNew->GetFilePath(); CString strOldPath = pFileOld->GetFilePath(); CString strBakPath = pFileOld->GetFilePath(); int i = strBakPath.ReverseFind('.'); if(i >= 0) strBakPath = strBakPath.Left(i); strBakPath = strBakPath + _T(".bak"); pFileOld->Close(); pFileNew->Close(); delete pFileNew; CFileFind mFileFind; if(mFileFind.FindFile(strBakPath)) CFile::Remove(strBakPath); CFile::Rename(strOldPath, strBakPath); CFile::Rename(strNewPath, strOldPath); DBF_CHECK_ERROR( m_DBFile.Open(strOldPath, m_nOpenFlag), TG_DBF_ERROR_DBFILE_OPEN); } m_nEditMode = noMode; m_bNew = TRUE; return TRUE; } BOOL CDBFTableDef::CreateTable(LPCTSTR lpszName) { assert(!IsOpen()); if (!lpszName) return FALSE; 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), TG_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() - TG_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(IsOpen()); m_pOldDBFHead = new DBF_HEAD; memcpy(m_pOldDBFHead, &m_DBFHead, sizeof(DBF_HEAD)); 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() - TG_DBF_CENTURY; m_DBFHead.last_update[1] = curDate.GetMonth(); m_DBFHead.last_update[2] = curDate.GetDay(); m_nEditMode = modify; return; } void CDBFTableDef::ModifyField(short nIndex, FIELD_REC *pFieldRec) { if (m_nEditMode == noMode || nIndex > m_DBFFields.m_nFieldCount) return; m_DBFFields.m_pFields[nIndex] = *pFieldRec; } void CDBFTableDef::MoveField(short nIndex, short nNewIndex) { if (m_nEditMode == noMode || nIndex > m_DBFFields.m_nFieldCount || nNewIndex > m_DBFFields.m_nFieldCount) return; 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() { if (m_nEditMode == noMode) return; 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; } } long TGGetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, COleVariant& varValue) { // Clear out variant varValue.Clear(); varValue.vt = VT_EMPTY; long lLen; long nOffset = pFieldRec->field_offset; switch(pFieldRec->field_type) { case FLD_TYPE_CHARACTER: { lLen = pFieldRec->len_info.char_len; char *buffer = new char[lLen+1]; memset(buffer, 0, lLen+1); //char* buffer = strValue.GetBuffer(lLen + 1); memcpy(buffer, &pRec[nOffset], lLen); buffer[lLen] = '\0'; CTDbfString _Value(buffer); delete [] buffer; CString strValue = _Value.toCString(); //strValue.ReleaseBuffer(lLen + 1); if(pFieldRec->field_flag != FLD_FLAG_BINARY) strValue.TrimRight(); 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] <= 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: { lLen = pFieldRec->len_info.num_size.len; //char* buffer = strValue.GetBuffer(lLen + 1); char *buffer = new char[lLen+1]; memcpy(buffer, &pRec[nOffset], lLen); buffer[lLen] = '\0'; //strValue.ReleaseBuffer(lLen + 1); CString strValue(buffer); delete [] buffer; varValue = strValue; } } return lLen; } void TGSetFieldValue(DBF_CHAR* pRec, FIELD_REC* pFieldRec, const COleVariant& var) { 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) { CTDbfString strValue = varValue.bstrVal; strncpy(&pRec[nOffset], strValue.toLPCSTR(), min((int)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(_T("%s.%uf"),_T("%"),bDec); strValue.Format(strFormat,varValue.dblVal); } if(strValue.GetLength() > lLen) { if(strValue.GetAt(lLen) == '.') strValue = ' ' + strValue; strValue = strValue.Left(lLen); } CTDbfString _Value(strValue); strncpy(&pRec[nOffset + (lLen - _Value.GetLength())], _Value.toLPCSTR(), _Value.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(_T("%d"),dte.GetYear()); CTDbfString _Value(strValue); strncpy(&pRec[nOffset + 4 - _Value.GetLength()], _Value.toLPCSTR(), _Value.GetLength()); strValue.Format(_T("%d"),dte.GetMonth()); _Value = strValue; strncpy(&pRec[nOffset + 6 - _Value.GetLength()], _Value.toLPCSTR(), _Value.GetLength()); strValue.Format(_T("%d"),dte.GetDay()); _Value = strValue; strncpy(&pRec[nOffset + 8 - _Value.GetLength()], _Value.toLPCSTR(), _Value.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: { CTDbfString strValue = varValue.boolVal == TRUE ? "T" : "F"; strncpy(&pRec[nOffset], strValue.toLPCSTR(), 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 strTmp; strTmp.Format(_T("%u"),varValue.ulVal); CTDbfString strOffsetRec(strTmp); memcpy(&pRec[nOffset + (lLen - strOffsetRec.GetLength())], strOffsetRec.toLPCSTR(), 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(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), TG_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), TG_DBF_ERROR_DBFILE_OPEN); return FALSE; } m_nOpenFlag = nNewFlag; return TRUE; }