www.pudn.com > pueblo.zip > ChDb.cpp
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
Chaco database implementation
----------------------------------------------------------------------------*/
#include "headers.h"
#include
#include
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include
#ifdef CH_UNIX
#include
#include
#define _MAX_PATH MAXPATHLEN
#define _O_BINARY 0
#define _O_RDONLY O_RDONLY
#define _O_WRONLY O_WRONLY
#define _O_CREAT O_CREAT
#define _O_EXCL O_EXCL
#define _S_IREAD S_IREAD
#define _S_IWRITE S_IWRITE
#endif
#include
#include
#include
#if defined( CH_MSW) && defined( CH_ARCH_16 )
#include
#endif
#include "ChNdbm.h"
/*----------------------------------------------------------------------------
Macros:
----------------------------------------------------------------------------*/
#if defined( CH_MSW )
#define strcpy lstrcpy
#define strcat lstrcat
#define strlen lstrlen
#if defined( CH_ARCH_16 )
#define strchr _fstrchr
#define strrchr _fstrrchr
#define access _access
#endif // defined( CH_ARCH_16 )
#endif // defined( CH_MSW )
#ifdef CH_UNIX
#define _access access
#endif
/*----------------------------------------------------------------------------
ChDBKey class
----------------------------------------------------------------------------*/
// Constructors
ChDBKey::ChDBKey( const string& strKey )
{
#ifdef CH_MSW
m_lKeySize = strKey.GetLength();
#else
m_lKeySize = strKey.length();
#endif
ASSERT( m_lKeySize );
m_pstrDBKey = new char[m_lKeySize + 1];
ASSERT( m_pstrDBKey );
strcpy( m_pstrDBKey, strKey );
m_lAllocSize = m_lKeySize + 1;
}
ChDBKey::ChDBKey( pstr pstrKey )
{
m_lKeySize = strlen( pstrKey );
ASSERT( m_lKeySize );
m_pstrDBKey = new char[ m_lKeySize + 1];
ASSERT( m_pstrDBKey );
strcpy( m_pstrDBKey, pstrKey );
m_lAllocSize = m_lKeySize + 1;
}
ChDBKey::ChDBKey( chint32 lKey )
{
m_pstrDBKey = new char[ 20];
ASSERT( m_pstrDBKey );
::wsprintf( m_pstrDBKey, "%ld", lKey );
m_lKeySize = lstrlen( m_pstrDBKey );
m_lAllocSize = 20;
}
ChDBKey::ChDBKey( ptr pData, chint32 lSize )
{
if ( lSize )
{
m_pstrDBKey = new char[ lSize];
ASSERT( m_pstrDBKey );
ChMemCopy( m_pstrDBKey, pData, lSize );
m_lKeySize = lSize;
m_lAllocSize = m_lKeySize;
}
else
{
m_pstrDBKey = NULL;
m_lAllocSize = m_lKeySize = 0;
}
}
ChDBKey::ChDBKey( const ChDBKey& key )
{
m_lKeySize = key.m_lKeySize;
m_lAllocSize = key.m_lKeySize;
if ( m_lKeySize )
{
ASSERT( m_lKeySize );
m_pstrDBKey = new char[ m_lKeySize];
ASSERT( m_pstrDBKey );
ChMemCopy( m_pstrDBKey, key.m_pstrDBKey, m_lKeySize );
}
else
{
m_pstrDBKey = NULL;
m_lAllocSize = m_lKeySize = 0;
}
}
// Destructor
ChDBKey::~ChDBKey()
{
if ( m_pstrDBKey )
{
delete []m_pstrDBKey;
}
}
/*----------------------------------------------------------------------------
ChDBKey operators
----------------------------------------------------------------------------*/
const ChDBKey& ChDBKey::operator=( const ChDBKey newKey )
{
if ( m_pstrDBKey != newKey.m_pstrDBKey )
{
if ( newKey.m_lKeySize > m_lAllocSize )
{
delete []m_pstrDBKey;
ASSERT( m_pstrDBKey );
m_pstrDBKey = new char[ newKey.m_lKeySize];
m_lAllocSize = newKey.m_lKeySize;
}
m_lKeySize = newKey.m_lKeySize;
ChMemCopy( m_pstrDBKey, newKey.m_pstrDBKey, m_lKeySize );
}
return *this;
}
const ChDBKey& ChDBKey::operator=( const string& strKey )
{
#ifdef CH_MSW
chint32 iLength = strKey.GetLength();
#else
chint32 iLength = strKey.length();
#endif
if ( iLength > m_lAllocSize )
{
delete []m_pstrDBKey;
m_pstrDBKey = new char[ iLength + 1];
ASSERT( m_pstrDBKey );
m_lAllocSize = iLength + 1;
}
m_lKeySize = iLength;
strcpy( m_pstrDBKey, strKey );
return *this;
}
const ChDBKey& ChDBKey::operator=( chint32 lKey )
{
if ( 20 > m_lAllocSize )
{
delete []m_pstrDBKey;
m_pstrDBKey = new char[ 20 ];
m_lAllocSize = 20;
}
::wsprintf( m_pstrDBKey, "%ld", lKey );
m_lKeySize = lstrlen( m_pstrDBKey );
return *this;
}
/*----------------------------------------------------------------------------
ChDBData
----------------------------------------------------------------------------*/
// Constructor
ChDBData::ChDBData( const string& strData )
{
#ifdef CH_MSW
m_lAllocSize = m_lDataSize = strData.GetLength();
#else
m_lAllocSize = m_lDataSize = strData.length();
#endif
if ( m_lDataSize )
{
m_pData = new char[ m_lDataSize + 1];
m_lAllocSize++;
ASSERT( m_pData );
strcpy( (pstr)m_pData, strData );
}
else
{
m_pData = NULL;
}
}
ChDBData::ChDBData( const ChDBData& chData )
{
m_lAllocSize = m_lDataSize = chData.m_lDataSize;
if ( m_lDataSize )
{
m_pData = new char[ m_lDataSize];
ASSERT( m_pData );
ChMemCopy( m_pData, chData.m_pData, m_lDataSize );
}
else
{
m_pData = NULL;
}
}
ChDBData::ChDBData( const pstr pstrData )
{
m_lAllocSize = m_lDataSize = lstrlen( pstrData );
if ( m_lDataSize )
{
m_pData = new char[ m_lDataSize + 1];
m_lAllocSize++;
ASSERT( m_pData );
strcpy( (pstr)m_pData, pstrData );
}
else
{
m_pData = NULL;
}
}
ChDBData::ChDBData( const ptr pData, chint32 lSize )
{
if ( lSize )
{
m_pData = new char[ lSize];
ASSERT( m_pData );
ChMemCopy( m_pData, pData, lSize );
m_lAllocSize = m_lDataSize = lSize;
}
else
{
m_pData = NULL;
m_lAllocSize = m_lDataSize = 0;
}
}
//Destructor
ChDBData::~ChDBData()
{
if ( m_pData )
{
delete []m_pData;
}
}
const ChDBData& ChDBData::operator=( const ChDBData newData )
{
if ( m_pData != newData.m_pData )
{
if ( newData.m_lDataSize > m_lAllocSize )
{
delete []m_pData;
m_pData = new char[ newData.m_lDataSize];
ASSERT( m_pData );
m_lAllocSize = newData.m_lDataSize;
}
m_lDataSize = newData.m_lDataSize;
ChMemCopy( m_pData, newData.m_pData, m_lDataSize );
}
return *this;
}
const ChDBData& ChDBData::operator=( const pstr pstrData )
{
m_lDataSize = lstrlen( pstrData );
if ( (m_lDataSize + 1) > m_lAllocSize )
{
delete []m_pData;
m_pData = new char[ m_lDataSize + 1];
m_lAllocSize = m_lDataSize + 1;
ASSERT( m_pData );
}
strcpy( (pstr)m_pData, pstrData );
return *this;
}
/*----------------------------------------------------------------------------
ChDataBase class
----------------------------------------------------------------------------*/
// Constructor
ChDataBase::ChDataBase( const char* pstrDBName )
{
// Allocate buffer to store the file name
m_pstrFile = new char[_MAX_PATH];
ASSERT( m_pstrFile );
if ( !pstrDBName )
{
pstr pstrExt;
// Get the temp file name
pstrDBName = m_pstrFile;
#if defined( CH_MSW ) && defined( CH_ARCH_16 )
GetTempFileName( GetTempDrive( 0 ), TEXT( "CH" ), 0, m_pstrFile );
// remove the extension
pstrExt = _fstrrchr( pstrDBName, TEXT( '.' ));
#elif defined( CH_MSW ) && defined( CH_ARCH_32 )
{
char strTemp[_MAX_PATH];
GetTempPath( _MAX_PATH, strTemp );
GetTempFileName( strTemp, TEXT( "CH" ), 0, m_pstrFile );
// remove the extension
pstrExt = strrchr( pstrDBName, TEXT( '.' ));
}
#elif defined( CH_UNIX )
{
strcpy( pstrDBName, tempnam( 0, "CH" ) );
pstrExt = 0;
}
#endif
if ( pstrExt )
{
*pstrExt = TEXT( '\0' );
}
m_boolValid = false;
}
else
{
m_boolValid = true;
::strcpy( m_pstrFile, pstrDBName );
// check if this is a valid database
char strDBName[MAX_PATH];
strcpy(strDBName, m_pstrFile);
strcat(strDBName, ".pag");
#if defined( CH_MSW ) && defined( CH_ARCH_32 )
if ( ::GetFileAttributes( strDBName ) == 0xFFFFFFFF )
{
m_boolValid = false;
}
#else
if (_access( strDBName, 0 ))
{
m_boolValid = false;
}
#endif
if ( m_boolValid )
{
strcpy(strDBName, m_pstrFile);
strcat(strDBName, ".dir");
#if defined( CH_MSW ) && defined( CH_ARCH_32 )
if ( ::GetFileAttributes( strDBName ) == 0xFFFFFFFF )
{
m_boolValid = false;
}
#else
if (access( strDBName, 0 ))
{
m_boolValid = false;
}
#endif
}
}
m_pDataBaseID = NULL;
m_dbFlags = 0;
}
// destructor
ChDataBase::~ChDataBase()
{
if ( m_pDataBaseID )
{
dbm_close( (pDBM)m_pDataBaseID );
}
if ( m_pDataBaseID && ( m_dbFlags & CHDB_DELETEONCLOSE ))
{// Delete the .dir and .pag files
char astrFile[_MAX_PATH];
#if defined( CH_ARCH_16 )
strcpy(astrFile, m_pstrFile);
strcat(astrFile, ".dir");
// delete the file
remove( astrFile );
strcpy(astrFile, m_pstrFile);
strcat(astrFile, ".pag");
// delete the file
remove( astrFile );
#else
strcpy(astrFile, m_pstrFile);
strcat(astrFile, ".dir");
// delete the file
DeleteFile( astrFile );
strcpy(astrFile, m_pstrFile);
strcat(astrFile, ".pag");
// delete the file
DeleteFile( astrFile );
#endif
}
if ( m_pstrFile )
{
delete []m_pstrFile;
}
}
/*----------------------------------------------------------------------------
ChDataBase public methods
----------------------------------------------------------------------------*/
bool ChDataBase::OpenDB( chuint32 flOpenFlags)
{
// Allocate buffer to store the file name
// save the user flags
m_dbFlags = flOpenFlags;
int iFlags = _O_BINARY;
iFlags |= (m_dbFlags & CHDB_READ ) ? _O_RDONLY : 0;
iFlags |= (m_dbFlags & CHDB_WRITE ) ? _O_WRONLY : 0;
iFlags |= (m_dbFlags & CHDB_CREATE ) ? _O_CREAT : 0;
iFlags |= (m_dbFlags & CHDB_FAILIFEXISTS ) ? _O_EXCL : 0;
m_pDataBaseID = (ptr)dbm_open( m_pstrFile, iFlags, _S_IREAD | _S_IWRITE );
return( m_pDataBaseID != NULL );
}
ChDBData ChDataBase::GetData( ChDBKey& dbKey ) const
{
datum data;
datum key;
key.dptr = dbKey.GetKey();
key.dsize= dbKey.GetKeySize();
data = dbm_fetch( (pDBM)m_pDataBaseID, key);
// Make a new data
ChDBData dbData( data.dptr, data.dsize);
return (dbData);
}
bool ChDataBase::SetData( const ChDBKey& dbKey, const ChDBData& data,
chuint32 flOptions ) const
{
chint32 iFlags = 0;
datum key;
datum dbdata;
iFlags |= (flOptions & CHDB_INSERT) ? DBM_INSERT : 0;
iFlags |= (flOptions & CHDB_REPLACE) ? DBM_REPLACE : 0;
key.dptr = dbKey.GetKey();
key.dsize= dbKey.GetKeySize();
dbdata.dptr = data.GetData();
dbdata.dsize= data.GetDataSize();
chint32 iRet = dbm_store( (pDBM)m_pDataBaseID, key,
dbdata, iFlags );
return (iRet == 0);
}
bool ChDataBase::Delete( ChDBKey& dbKey ) const
{
datum key;
key.dptr = dbKey.GetKey();
key.dsize= dbKey.GetKeySize();
chint32 iRet = dbm_delete( (pDBM)m_pDataBaseID, key );
return (iRet == 0);
}
ChDBKey ChDataBase::GetFirstKey()
{
datum key = dbm_firstkey( (pDBM)m_pDataBaseID );
ChDBKey dbKey( key.dptr, key.dsize );
return dbKey;
}
ChDBKey ChDataBase::GetNextKey( ChDBKey& dbKey ) const
{
datum key = dbm_nextkey( (pDBM)m_pDataBaseID );
ChDBKey dbNextKey( key.dptr, key.dsize );
return dbNextKey;
}
int ChDataBase::GetLastError()
{
return (int)dbm_error( (pDBM)m_pDataBaseID );
}