home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Objective Grid C++ Library.
- // Copyright (C) 1995,1996 ClassWorks, Stefan Hoenig.
- // All rights reserved.
- //
- // This source code is only intended as a supplement to
- // the Objective Grid Classes Reference and related
- // electronic documentation provided with the library.
- // See these sources for detailed information regarding
- // the Objective Grid product.
- //
-
- // dbfile.cpp : implemematation of the CDBaseFile class
- //
-
- #include "stdafx.h"
- #include "dbfile.h"
-
- static CString& StripTrailingChars (CString& sEdit, TCHAR cChar)
- {
- ASSERT(cChar != _T('\0'));
-
- // find beginning of trailing spaces by starting at beginning (DBCS aware)
- int nIndex = 0,
- nLast = -1;
- while (nIndex < sEdit.GetLength())
- {
- if (sEdit[nIndex] == cChar)
- {
- if (nLast == -1)
- nLast = nIndex;
- }
- else
- nLast = -1;
- nIndex += _tclen((const TCHAR *) sEdit + nIndex);
- }
-
- if (nLast != -1)
- {
- // truncate at trailing space start
- sEdit = sEdit.Left(nLast);
- }
-
- return sEdit;
- }
-
- static void StripLeadingBlanks(CString& sEdit)
- {
- // find first non-space character
- LPCTSTR lpsz = sEdit;
- int n = 0;
- while (*lpsz == _T(' '))
- {
- lpsz = _tcsinc(lpsz);
- n++;
- }
-
- // fix up data
- if (n >= sEdit.GetLength())
- sEdit.Empty();
- else if (n > 0)
- sEdit = sEdit.Mid(n);
- }
-
- CDBaseFile::CDBaseFile()
- {
- recordBuf = NULL;
- fd = NULL;
- nRecordCount = 0;
- nCurrentRecord = -1;
- nFieldCount = 0;
- bWriteFlag = FALSE;
- }
-
- CDBaseFile::~CDBaseFile()
- {
- Close();
- }
-
- void CDBaseFile::Close()
- {
- if (fd)
- {
- Flush();
- delete recordBuf;
- for (int i = 0; i < nFieldCount; i++)
- delete fieldArray[i];
- fieldArray.RemoveAll();
- fclose(fd);
- }
- fd = NULL;
- }
-
- BOOL CDBaseFile::Open(LPCTSTR szFileName, BOOL readOnly)
- {
- fd = _tfopen (sFileName = szFileName, (bReadOnly = readOnly) != FALSE ? _T("rb") : _T("rb+"));
-
- if (fd == 0)
- return FALSE;
-
- int nBufSize = InitFields ();
-
- recordBuf = new char[nBufSize+1];
-
- return Seek(1);
- }
-
- BOOL CDBaseFile::Seek(long nRecord)
- {
- // move to new record and flush changes of previous record
- if (nRecord < 0 || nRecord > nRecordCount)
- return FALSE;
- else if (nRecord == nCurrentRecord)
- return TRUE;
-
- // new record
- if (bWriteFlag)
- Flush();
-
- nCurrentRecord = nRecord;
- long pos = (nRecord * size) + offset;
-
- if (nRecord == nRecordCount)
- {
- // New record
- memset(recordBuf, ' ', size);
- }
- else
- {
- fseek (fd, pos, 0);
- fread (recordBuf, size, 1, fd);
- recordBuf[size] = 0;
- }
-
- return TRUE;
- }
-
- void CDBaseFile::AddNew()
- {
- // determine structure of dbase file
- // and determine field types, offsets and lengths
-
- // new record
- if (bWriteFlag)
- Flush();
-
- nCurrentRecord = nRecordCount;
- memset(recordBuf, ' ', size);
- }
-
- void CDBaseFile::Flush()
- {
- // write all changes of the current record to the dbase file
-
- if (!bWriteFlag || bReadOnly)
- return;
-
- bWriteFlag = FALSE;
-
- long pos = (nCurrentRecord * size) + offset;
-
- fseek (fd, pos, 0);
- fwrite (recordBuf, size, 1, fd);
-
- if (nCurrentRecord == nRecordCount)
- {
- fseek (fd, 4L, 0);
- nRecordCount++;
- fwrite(&nRecordCount, 4, 1, fd);
- }
- }
-
- CField* CDBaseFile::GetField(int n) const
- {
- // returns field info
-
- ASSERT(n >= 0 && n <= nFieldCount);
- return (CField*) fieldArray.GetAt(n);
- }
-
- BOOL CDBaseFile::IsDeleted() const
- {
- // if record is deleted, a '*' is at the first position
-
- return *recordBuf != _T(' ');
- }
-
- BOOL CDBaseFile::GetValue(int n, CString& result) const
- {
- // read value from buffer
-
- ASSERT(n >= 0 && n <= nFieldCount);
-
- if (!(n >= 0 && n <= nFieldCount))
- return FALSE;
-
- result.Empty();
-
- CField* fld = GetField(n);
-
- // A note on DBCS/Unicode support.
- //
- // I assume that data in the dbase file are in ANSI/DBCS format.
- // If this application was compiled with _UNICODE switch,
- // data will be converted from single byte chars to wide chars.
-
- #ifdef _UNICODE
-
- // Convert ansi chars to wide chars
- char* psz = new char[fld->len+1];
-
- // read ansi chars
- strncpy(psz, recordBuf+fld->offset, fld->len);
- psz[fld->len] = _T('\0');
-
- // convert to wide char
- result = psz;
-
- delete psz;
-
- #else
-
- // simply copy chars to result string
- LPTSTR p = result.GetBuffer(fld->len+1);
-
- _tcsncpy(p, recordBuf+fld->offset, fld->len);
- p[fld->len] = _T('\0');
-
- result.ReleaseBuffer();
-
- #endif
-
- StripTrailingChars(result, _T(' '));
- StripLeadingBlanks(result);
-
- return TRUE;
- }
-
- BOOL CDBaseFile::SetValue(int n, LPCTSTR pszValue)
- {
- // write value to buffer
-
- ASSERT(n >= 0 && n <= nFieldCount);
-
- if (bReadOnly)
- return FALSE;
-
- if (!(n >= 0 && n <= nFieldCount))
- return FALSE;
-
- CField* fld = GetField(n);
-
- // A note on DBCS/Unicode support.
- //
- // I assume that data in the dbase file are in ANSI/DBCS format.
- // If this application was compiled with _UNICODE switch,
- // data will be converted from single byte chars to wide chars.
-
- int len;
-
- #ifdef _UNICODE
-
- // Convert wide chars to ansi chars
- char* pastring = new char[fld->len+1];
- WideCharToMultiByte (CP_ACP, 0, pszValue, -1,
- pastring, fld->len, NULL, NULL);
-
-
- strncpy(recordBuf+fld->offset, pastring, len = strlen(pastring));
-
- delete pastring;
- #else
-
- // simply copy chars to buffer
- _tcsncpy(recordBuf+fld->offset, pszValue, len = _tcslen(pszValue));
- #endif
-
- // fill up with blanks
- while (len < fld->len)
- recordBuf[fld->offset+len++] = _T(' ');
-
- bWriteFlag = TRUE;
-
- return TRUE;
- }
-
- int CDBaseFile::InitFields ()
- {
- // determine structure of dbase file
- // and determine field types, offsets and lengths
-
- fseek (fd, 4L, 0);
- fread (&nRecordCount, 4, 1, fd);
-
- if (nRecordCount == 0L)
- AfxThrowFileException (CFileException::endOfFile);
-
- fread (&offset, 2, 1, fd);
- fread (&size, 2, 1, fd);
-
- nFieldCount = (offset-33)/32;
-
- int off = 1; // field offset
-
- long pos = 32;
- for (int i = 0; i < nFieldCount; i++, pos += 32)
- {
- CField* fld = new CField;
- fieldArray.SetAtGrow(i, fld);
- fseek (fd, pos, 0);
- fread (fld->name, 10, 1, fd);
- fld->name[10] = 0;
-
- fseek (fd, pos+11, 0);
- fread (&fld->type, 1, 1, fd);
-
- fseek (fd, pos+16, 0);
- unsigned char width, decimals;
- fread (&width, 1, 1, fd);
- fread (&decimals, 1, 1, fd);
- fld->len = width;
- fld->display_width = fld->width = width;
- fld->decimals = decimals;
- fld->offset = off;
- off += width;
-
- int l = strlen(fld->name);
- if (fld->width < l)
- fld->width = (short)l;
- }
-
- return off;
- }
-