#include "stdafx.h"
#include "CeDb.h"
#include <winnls.h>
char* WideToAscii( char* s, const wchar_t* ws )
{
char* pszSave = (char*) s;
while (*s++ = (char) *ws++ )
;
return (pszSave);
}
bool CeDb::ReadRec(CeDbRecord& rec)
{
ASSERT(IsOpen());
if (! rec.m_bLocalAlloc && rec.m_pProps)
delete[] rec.m_pProps;
rec.m_pProps = NULL;
rec.m_cbProps = 0;
rec.m_bLocalAlloc = true;
// Getting a record WILL overwrite the old values
rec.m_wProps = 0;
// read all properties
rec.m_oid = ::CeReadRecordProps(
m_hDb, // this database
CEDB_ALLOWREALLOC, // no realloc
&rec.m_wProps, // number of properties in THIS record
NULL, // get all columnsfor THIS record
(BYTE**) &rec.m_pProps, // the properties values
&rec.m_cbProps // size of the allocated space
);
return (rec.m_oid && rec.m_pProps && rec.m_wProps);
}
//
// CEVT_BLOB A CEBLOB structure.
// CEVT_FILETIME A FILETIME structure.
// CEVT_I2 A 16-bit signed integer.
// CEVT_I4 A 32-bit signed integer.
// CEVT_LPWSTR A null-terminated string.
// CEVT_UI2 A 16-bit unsigned integer.
// CEVT_UI4 A 32-bit unsigned integer.
//
// And beginning in 2.11
// CEVT_BOOL A boolean value.
// CEVT_R8 A double floating point value.
//
bool CeDbRecord::GetIndexVal(int nProp, SHORT& iProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_I2);
iProp = m_pProps[nProp].val.iVal;
return true;
}
bool CeDbRecord::GetIndexVal(int nProp, USHORT& uiProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_UI2);
uiProp = m_pProps[nProp].val.uiVal;
return true;
}
bool CeDbRecord::GetIndexVal(int nProp, LONG& lProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_I4);
lProp = m_pProps[nProp].val.lVal;
return true;
}
bool CeDbRecord::GetIndexVal(int nProp, ULONG& ulProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_UI4);
ulProp = m_pProps[nProp].val.ulVal;
return true;
}
bool CeDbRecord::GetIndexVal(int nProp, FILETIME& ftProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_FILETIME);
ftProp = m_pProps[nProp].val.filetime;
return true;
}
#ifdef CEVT_BOOL
#pragma warning(disable: 4800)
bool CeDbRecord::GetIndexVal(int nProp, bool& bProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_BOOL);
bProp = m_pProps[nProp].val.boolVal;
return true;
}
#endif
#ifdef CEVT_R8
bool CeDbRecord::GetIndexVal(int nProp, double& dblProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_R8);
dblProp = m_pProps[nProp].val.dblVal;
return true;
}
#endif
bool CeDbRecord::GetIndexVal(int nProp, CEBLOB& blobProp) const
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_BLOB);
return true;
}
inline char HiNibble(BYTE by) { return (by >> 4); }
inline char LoNibble(BYTE by) { return (by & 0x0F); }
static CeString GetBlob(DWORD dwSize, BYTE* lpByte)
{
CeString str;
LPTSTR lpsz = str.GetBufferSetLength(3 * dwSize);
for (DWORD ii = 0; ii < dwSize; ii++)
{
BYTE byTmp;
byTmp = HiNibble(*lpByte);
*lpsz++ = (TCHAR) (byTmp < 0x0A) ? _T('0') + byTmp: _T('A') + (byTmp - 0x0A);
byTmp = LoNibble(*lpByte);
*lpsz++ = (TCHAR) (byTmp < 0x0A) ? _T('0') + byTmp: _T('A') + (byTmp - 0x0A);
*lpsz++ = _T(' ');
lpByte++;
}
*lpsz = 0;
str.ReleaseBuffer();
return str;
}
// valid for all types, limited to 256 bytes for Blob
bool CeDbRecord::GetIndexVal(int nProp, CeString& strProp) const
{
//ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
{
strProp.Empty();
return false;
}
switch ( LOWORD(m_pProps[nProp].propid) )
{
case CEVT_BLOB:
strProp = GetBlob(m_pProps[nProp].val.blob.dwCount, m_pProps[nProp].val.blob.lpb);
break;
case CEVT_FILETIME:
{
SYSTEMTIME st;
BOOL bSuccess = ::FileTimeToSystemTime(&m_pProps[nProp].val.filetime, &st);
if (! bSuccess || st.wYear > 9999)
{
strProp.Empty();
return true;
}
CeString strTime;
::GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE,
&st, NULL, strProp.GetBufferSetLength(32), 32);
strProp.ReleaseBuffer();
::GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS,
&st, NULL, strTime.GetBufferSetLength(32), 32);
strTime.ReleaseBuffer();
strProp += _T(" ");
strProp += strTime;
}
break;
case CEVT_I2:
strProp = CeString(m_pProps[nProp].val.iVal);
break;
case CEVT_I4:
strProp = CeString(m_pProps[nProp].val.lVal);
break;
case CEVT_LPWSTR:
#ifdef UNICODE
strProp = m_pProps[nProp].val.lpwstr;
#else
WideToAscii( strProp.GetBufferSetLength( wcslen(m_pProps[nProp].val.lpwstr) ),
m_pProps[nProp].val.lpwstr );
strProp.ReleaseBuffer();
#endif
break;
case CEVT_UI2:
strProp = CeString((ULONG)m_pProps[nProp].val.uiVal);
break;
case CEVT_UI4:
strProp = CeString((ULONG)m_pProps[nProp].val.ulVal);
break;
#ifdef CEVT_BOOL
case CEVT_BOOL:
strProp = m_pProps[nProp].val.boolVal ? _T("true"): _T("false");
break;
#endif
#ifdef CEVT_R8
case CEVT_R8:
strProp = CeString(m_pProps[nProp].val.dblVal);
break;
#endif
default:
return false;
}
return true;
}
bool CeDbRecord::SetIndexVal(int nProp, SHORT iProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_I2);
m_pProps[nProp].val.iVal = iProp;
return true;
}
bool CeDbRecord::SetIndexVal(int nProp, USHORT uiProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_UI2);
m_pProps[nProp].val.uiVal = uiProp;
return true;
}
bool CeDbRecord::SetIndexVal(int nProp, LONG lProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_I4);
m_pProps[nProp].val.lVal = lProp;
return true;
}
bool CeDbRecord::SetIndexVal(int nProp, ULONG ulProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_UI4);
m_pProps[nProp].val.ulVal = ulProp;
return true;
}
bool CeDbRecord::SetIndexVal(int nProp, FILETIME ftProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_FILETIME);
m_pProps[nProp].val.filetime = ftProp;
return true;
}
#ifdef CEVT_BOOL
bool CeDbRecord::SetIndexVal(int nProp, bool bProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_BOOL);
m_pProps[nProp].val.boolVal = bProp;
return true;
}
#endif
#ifdef CEVT_R8
bool CeDbRecord::SetIndexVal(int nProp, double dblProp)
{
// ASSERT(nProp < m_wProps && nProp >= 0);
if (nProp < 0 || nProp >= m_wProps)
return false;
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_R8);
m_pProps[nProp].val.dblVal = dblProp;
return true;
}
#endif
CEPROPVAL* CeDbRecord::DupProps(CEPROPVAL* pPropsOrig, WORD wProps, DWORD cbNewProps)
{
// allocate a buffer
CEPROPVAL* pProps = (CEPROPVAL*) new BYTE[cbNewProps];
ASSERT(NULL != pProps);
if (NULL == pProps)
return NULL;
// assumes structure and pointer are word aligned
BYTE* pData = (BYTE*) pProps + sizeof CEPROPVAL * wProps;
for (WORD ii = 0; ii < wProps; ii++)
{
// shallow copy, don't require extra memory space to store the value
pProps[ii] = pPropsOrig[ii];
// check if deep copy required
if ( CEVT_BLOB == LOWORD(pPropsOrig[ii].propid) )
{
// Note: could be a NULL value
if (0 == pPropsOrig[ii].val.blob.dwCount || NULL == pProps[ii].val.blob.lpb)
continue;
// NOTE: this has to be on a WORD boundry!!!
DWORD dwLen = pPropsOrig[ii].val.blob.dwCount;
pProps[ii].val.blob.lpb = pData;
memcpy( pProps[ii].val.blob.lpb, pPropsOrig[ii].val.blob.lpb, dwLen );
// required so character indexes are even
pData += (dwLen + (dwLen % sizeof WORD));
}
else if ( CEVT_LPWSTR == LOWORD(pPropsOrig[ii].propid) )
{
// Note: could be a NULL value
if (NULL == pPropsOrig[ii].val.lpwstr)
continue;
// note: results are always word alligned
// since the characters are the size of the word
DWORD dwLen = (wcslen(pPropsOrig[ii].val.lpwstr) + 1) * sizeof WCHAR;
pProps[ii].val.lpwstr = (WCHAR *) pData;
memcpy(pData, pPropsOrig[ii].val.lpwstr, dwLen);
pData += dwLen;
}
}
return pProps;
}
bool CeDbRecord::SetIndexVal(int nProp, CEBLOB blobProp)
{
ASSERT(nProp < m_wProps && nProp >= 0);
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_BLOB);
if (m_pProps[nProp].val.blob.dwCount < blobProp.dwCount)
{
// need to reallocate the ENTIRE record and copy in this one
// Note: THIS will ONLY work when EXPANDING the allocated memory
DWORD cbProps = (blobProp.dwCount - m_pProps[nProp].val.blob.dwCount);
//cbProps += (dwLen % sizeof WORD)
m_pProps[nProp].val.blob.lpb = blobProp.lpb;
m_pProps[nProp].val.blob.dwCount = blobProp.dwCount;
CEPROPVAL* pProps = DupProps(m_pProps, m_wProps, cbProps);
if (NULL == pProps)
return false;
if (m_bLocalAlloc)
::LocalFree(m_pProps);
else
delete[] (BYTE*) m_pProps;
m_pProps = pProps;
m_cbProps = cbProps;
m_bLocalAlloc = false;
}
else
{
memcpy(m_pProps[nProp].val.blob.lpb, blobProp.lpb, blobProp.dwCount);
m_pProps[nProp].val.blob.dwCount = blobProp.dwCount;
}
return false;
}
bool CeDbRecord::SetIndexVal(int nProp, LPCWSTR lpszProp)
{
ASSERT(nProp < m_wProps && nProp >= 0);
ASSERT(LOWORD(m_pProps[nProp].propid) == CEVT_LPWSTR);
int nOldLen = (m_pProps[nProp].val.lpwstr) ? wcslen(m_pProps[nProp].val.lpwstr) + 2 : 0;
int nNewLen = wcslen(lpszProp) + 2;
if (nOldLen < nNewLen)
{
// need to reallocate the ENTIRE record and copy in this one
// Note: THIS will ONLY work when EXPANDING the allocated memory
DWORD cbProps = m_cbProps + (nNewLen - nOldLen) * sizeof WCHAR;
// set pointer
m_pProps[nProp].val.lpwstr = (LPWSTR) lpszProp;
CEPROPVAL* pProps = DupProps(m_pProps, m_wProps, cbProps);
if (NULL == pProps)
return false;
if (m_bLocalAlloc)
::LocalFree(m_pProps);
else
delete[] (BYTE*) m_pProps;
m_cbProps = cbProps;
m_pProps = pProps;
m_bLocalAlloc = false;
}
else
wcscpy(m_pProps[nProp].val.lpwstr, lpszProp);
return true;
}
bool CeDbRecord::AddProp(WORD wProp, WORD wType)
{
CEPROPVAL* pProps = NULL;
if (NULL == m_pProps)
{
// append to end
pProps = (CEPROPVAL*) new BYTE[sizeof CEPROPVAL];
DWORD dwErr = GetLastError();
ASSERT(NULL != pProps);
}
else
{
{
// enlarge
pProps = (CEPROPVAL*) new BYTE[m_cbProps + sizeof CEPROPVAL];
memcpy(pProps, m_pProps, m_cbProps);
}
DWORD dwErr = GetLastError();
ASSERT(NULL != pProps);
// move data from end
for (int ii = m_wProps - 1; ii >= 0 ; ii--)
{
DWORD dwLen;
if (CEVT_BLOB == LOWORD(pProps[ii].propid))
{
// NOTE: this has to be on a WORD boundry!!!
dwLen = pProps[ii].val.blob.dwCount;
if (0 != dwLen && NULL != pProps[ii].val.blob.lpb)
pProps[ii].val.blob.lpb = (BYTE*) memmove( pProps[ii].val.blob.lpb + sizeof CEPROPVAL, pProps[ii].val.blob.lpb, dwLen);
}
else if (CEVT_LPWSTR == LOWORD(pProps[ii].propid))
{
// note: results are always word alligned
// since the characters are the size of the word
dwLen = pProps[ii].val.lpwstr ? (wcslen(pProps[ii].val.lpwstr) + 1) * sizeof WCHAR: 0;
if (0 != dwLen)
pProps[ii].val.lpwstr = (WCHAR*) memmove(pProps[ii].val.lpwstr + sizeof CEPROPVAL, pProps[ii].val.lpwstr, dwLen);
}
}
}
if (m_bLocalAlloc)
::LocalFree(m_pProps);
else
delete[] (BYTE*) m_pProps;
m_pProps = pProps;
m_bLocalAlloc = false;
m_cbProps += sizeof CEPROPVAL;
m_wProps++;
ZeroMemory(&m_pProps[m_wProps-1], sizeof CEPROPVAL);
m_pProps[m_wProps-1].propid = MAKELPARAM(wType, wProp);
return true;
}
bool CeDbRecord::RemProp(int nIndex)
{
// memmove();
// DupProps();
return false;
}
bool CeDbRecord::RemProp(WORD wProp)
{
// int nProp = FindProp(wProp);
// memmove();
// DupProps();
return false;
}