// XBitArray.h Version 1.2
//
// Author: Hans Dietrich
// hdietrich2@hotmail.com
//
// Description:
// XBitArray.h implements CXBitArray(), a class to handle bit operations
// on an array of BYTEs.
//
// History
// Version 1.2 - 2004 February 10
// - Initial public release
//
// Public APIs:
// NAME DESCRIPTION
// -------------------- -------------------------------------------------------
// CXBitArray() #1 Construct uninitialized CXBitArray object
// CXBitArray() #2 Construct CXBitArray object from existing array
// CXBitArray() #3 Construct CXBitArray object with array allocation
// CXBitArray() #4 Construct CXBitArray object from file
// CXBitArray() #5 Construct CXBitArray object from registry
// ~CXBitArray() Save bit array to file and/or registry and deallocate bit array
// Attach() Attach an existing bit array to a CXBitArray object
// Count() Return counts of bits set to 0 and bits set to 1
// Find() Find next bit that has the value specified by bit_value
// Get() Get bit value
// GetArraySizeBits() Get size of bit array in bits
// GetArraySizeBytes() Get size of bit array in bytes
// GetBitNo() Convert bit mask to bit number
// GetBitPos() Convert bit number to byte and bit indexes and bit mask
// GetPersistFileName() Get persist file name
// GetRegistryKeyName() Get registry key name
// GetRegistryValueName() Get registry value name
// Init() Initialize CXBitArray object
// operator [] Get bit value at a bit index
// operator LPBYTE Get address of bit array
// ReadPersistFile() Read bit array from file
// ReadRegistry() Read bit array from registry
// Set() Set bit value
// SetAll() Set all bits to a value
// SetPersistFileName() Set persist file name
// SetRegistryNames() Set registry key and value names
// ToString() Returns a string that represents the bit array
// WritePersistFile() Write bit array to file
// WriteRegistry() Write bit array to registry
//
// This software is released into the public domain. You are free to use it
// in any way you like, except that you may not sell this source code.
//
// This software is provided "as is" with no expressed or implied warranty.
// I accept no liability for any damage or loss of business that this software
// may cause.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef XBITARRAY_H
#define XBITARRAY_H
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
// (needed for _ASSERTE)
#include <io.h>
#define XBITARRAY_TRACE ((void)0)
///////////////////////////////////////////////////////////////////////////////
//
// If you want TRACE output you can uncomment the following lines:
//
//#undef XBITARRAY_TRACE
//#define XBITARRAY_TRACE TRACE
//
///////////////////////////////////////////////////////////////////////////////
// CXBitArray class
class CXBitArray
{
// Constructors / Destructors
public:
///////////////////////////////////////////////////////////////////////////////
//
// CXBitArray() #1
//
// Purpose: Construct uninitialized CXBitArray object
//
// Parameters: None
//
// Returns: None
//
CXBitArray()
{
XBITARRAY_TRACE(_T("in CXBitArray 1\n"));
m_pBitArray = NULL;
Init();
}
///////////////////////////////////////////////////////////////////////////////
//
// CXBitArray() #2
//
// Purpose: Construct CXBitArray object from existing array
//
// Parameters: pBitArray - address of bit array
// nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
//
// Returns: None
//
CXBitArray(BYTE *pBitArray, size_t nArraySizeBits, BOOL bit_value)
{
XBITARRAY_TRACE(_T("in CXBitArray 2\n"));
m_pBitArray = NULL;
Init(NULL, NULL, NULL, pBitArray, nArraySizeBits, bit_value);
}
///////////////////////////////////////////////////////////////////////////////
//
// CXBitArray() #3
//
// Purpose: Construct CXBitArray object with array allocation
//
// Parameters: nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
//
// Returns: None
//
CXBitArray(size_t nArraySizeBits, BOOL bit_value)
{
XBITARRAY_TRACE(_T("in CXBitArray 3\n"));
m_pBitArray = NULL;
Init(NULL, NULL, NULL, NULL, nArraySizeBits, bit_value);
}
///////////////////////////////////////////////////////////////////////////////
//
// CXBitArray() #4
//
// Purpose: Construct CXBitArray object from file
//
// Parameters: lpszPersistFile - name of file to read bit array from
// nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
// if it cannot be read from file
//
// Returns: None
//
// Notes: If the file specified by lpszPersistFile cannot be read,
// the bit array will be allocated according to nArraySizeBits
// and initialized to bit_value. Regardless of whether the
// file exists, the bit array will be saved to this file when
// the destructor is called.
//
// If the file specified by lpszPersistFile can be read, the
// size of the bit array is determined by the size of the file.
//
CXBitArray(LPCTSTR lpszPersistFile, size_t nArraySizeBits, BOOL bit_value)
{
XBITARRAY_TRACE(_T("in CXBitArray 4\n"));
m_pBitArray = NULL;
Init(lpszPersistFile, NULL, NULL, NULL, nArraySizeBits, bit_value);
}
///////////////////////////////////////////////////////////////////////////////
//
// CXBitArray() #5
//
// Purpose: Construct CXBitArray object from registry
//
// Parameters: lpszKeyName - key name (must not be NULL)
// lpszValueName - value name (may be NULL)
// nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
// if it cannot be read from registry
//
// Returns: None
//
// Notes: If the registry key specified by lpszKeyName cannot be read,
// the bit array will be allocated according to nArraySizeBits
// and initialized to bit_value. Regardless of whether the
// registry key exists, the bit array will be saved to this file
// when the destructor is called.
//
// If the registry key specified by lpszKeyName can be read, the
// size of the bit array is determined by the size of the registry
// value.
//
// If lpszValueName is NULL, the key's unnamed or default value
// will be used.
//
CXBitArray(LPCTSTR lpszKeyName,
LPCTSTR lpszValueName,
size_t nArraySizeBits,
BOOL bit_value)
{
XBITARRAY_TRACE(_T("in CXBitArray 5\n"));
m_pBitArray = NULL;
Init(NULL, lpszKeyName, lpszValueName, NULL, nArraySizeBits, bit_value);
}
///////////////////////////////////////////////////////////////////////////////
//
// ~CXBitArray()
//
// Purpose: Save bit array to file and/or registry and deallocate bit array
//
// Parameters: None
//
// Returns: None
//
virtual ~CXBitArray()
{
XBITARRAY_TRACE(_T("in ~CXBitArray\n"));
if (m_szPersistFile[0] != _T('\0'))
WritePersistFile(m_szPersistFile);
if (m_szKeyName[0] != _T('\0'))
WriteRegistry(m_szKeyName, m_szValueName);
if (m_bDeleteArray && m_pBitArray)
delete [] m_pBitArray;
m_pBitArray = NULL;
m_nArraySizeBytes = 0;
m_nArraySizeBits = 0;
}
///////////////////////////////////////////////////////////////////////////////
//
// Init()
//
// Purpose: Initialize CXBitArray object
//
// Parameters: lpszPersistFile - name of file to read bit array from
// lpszKeyName - key name
// : lpszValueName - value name - if lpszKeyName is not NULL, and
// lpszValueName is NULL, the key's unnamed or
// default value will be used
// pBitArray - address of bit array. If NULL, a new bit
// array will be allocated.
// nArraySizeBits - size of array in bits; rounded up to next
// multiple of 8
// bit_value - bit array will be initialized to this value
//
// Returns: None
//
// Notes: See Notes for CXBitArray #4 and #5.
//
void Init(LPCTSTR lpszPersistFile = NULL,
LPCTSTR lpszKeyName = NULL,
LPCTSTR lpszValueName = NULL,
BYTE *pBitArray = NULL,
size_t nArraySizeBits = 0,
BOOL bit_value = FALSE)
{
XBITARRAY_TRACE(_T("in Init: nArraySizeBits=%d\n"),
nArraySizeBits);
SetPersistFileName(lpszPersistFile);
SetRegistryNames(lpszKeyName, lpszValueName);
// if Init is being called again, delete the previous heap array
if (m_bDeleteArray && m_pBitArray)
delete [] m_pBitArray;
m_bDeleteArray = FALSE;
m_pBitArray = pBitArray;
m_nArraySizeBits = nArraySizeBits;
if (m_nArraySizeBits == 0)
m_nArraySizeBits = 1;
m_nArraySizeBytes = (m_nArraySizeBits + 7) / 8; // round up
m_nArraySizeBits = m_nArraySizeBytes * 8;
if (m_pBitArray)
SetAll(bit_value);
// read bit array from file if specified
if (m_szPersistFile[0] != _T('\0'))
{
ReadPersistFile(m_szPersistFile, m_nArraySizeBits, bit_value);
}
else if (m_szKeyName[0] != _T('\0'))
{
ReadRegistry(m_szKeyName, m_szValueName, m_nArraySizeBits,
bit_value);
}
if (m_pBitArray == NULL)
{
// allocate array if address is NULL
XBITARRAY_TRACE(_T("Init: allocating bit array for %d bytes\n"),
m_nArraySizeBytes);
m_pBitArray = new BYTE [m_nArraySizeBytes];
_ASSERTE(m_pBitArray);
m_bDeleteArray = TRUE; // ensure array will be deallocated
SetAll(bit_value);
}
if ((m_pBitArray != NULL) && (m_nArraySizeBytes > 0))
{
// one final check to ensure array is ok
_ASSERTE(!IsBadWritePtr(m_pBitArray, m_nArraySizeBytes));
if (IsBadWritePtr(m_pBitArray, m_nArraySizeBytes))
{
XBITARRAY_TRACE(_T("ERROR: bad pointer\n"));
}
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Attach()
//
// Purpose: Attach an existing bit array to a CXBitArray object
//
// Parameters: pBitArray - address of bit array (must not be NULL)
// nArraySizeBits - size of array in bits
//
// Returns: None
//
// Notes: Attach will associate the bit array specified by pBitArray
// with the CXBitArray object *without* initializing the bit
// array (unlike CXBitArray() #2, which always initializes
// the bit array). If a heap-allocated bit array is already
// associated with the CXBitArray object, it will be deallocated.
//
BOOL Attach(BYTE *pBitArray, size_t nArraySizeBits)
{
XBITARRAY_TRACE(_T("in Attach: nArraySizeBits=%d\n"),
nArraySizeBits);
// if already initialized, delete the previous heap array
if (m_bDeleteArray && m_pBitArray)
delete [] m_pBitArray;
m_bDeleteArray = FALSE;
m_pBitArray = NULL;
_ASSERTE(pBitArray);
if (!pBitArray)
{
XBITARRAY_TRACE(_T("ERROR: pBitArray is NULL\n"));
return FALSE;
}
_ASSERTE(nArraySizeBits > 0);
if (nArraySizeBits == 0)
{
XBITARRAY_TRACE(_T("ERROR: nArraySizeBits = 0\n"));
return FALSE;
}
_ASSERTE(((nArraySizeBits/8)*8) == nArraySizeBits);
if (((nArraySizeBits/8)*8) != nArraySizeBits)
{
XBITARRAY_TRACE(_T("ERROR: nArraySizeBits is not a multiple of 8\n"));
return FALSE;
}
m_pBitArray = pBitArray;
m_nArraySizeBits = nArraySizeBits;
if (m_nArraySizeBits == 0)
m_nArraySizeBits = 1;
m_nArraySizeBytes = (m_nArraySizeBits + 7) / 8; // round up
m_nArraySizeBits = m_nArraySizeBytes * 8;
// one final check to ensure array is ok
_ASSERTE(!IsBadWritePtr(m_pBitArray, m_nArraySizeBytes));
if (IsBadWritePtr(m_pBitArray, m_nArraySizeBytes))
{
XBITARRAY_TRACE(_T("ERROR: bad pointer\n"));
return FALSE;
}
return TRUE;
}
// Copy & Assignment - do not allow
private:
CXBitArray(const CXBitArray&);
CXBitArray& operator = (const CXBitArray&);
// Attributes
public:
///////////////////////////////////////////////////////////////////////////////
//
// Count()
//
// Purpose: Return counts of bits set to 0 and bits set to 1
//
// Parameters: bits_set_to_zero - pointer to the variable where the count of
// bits set to 0 is returned.
// bits_set_to_one - pointer to the variable where the count of
// bits set to 1 is returned.
//
// Returns: BOOL - TRUE = success
//
BOOL Count(size_t *bits_set_to_zero, size_t *bits_set_to_one) const
{
_ASSERTE(bits_set_to_zero && bits_set_to_one);
if ((bits_set_to_zero == NULL) || (bits_set_to_one == NULL))
return FALSE;
*bits_set_to_zero = 0;
*bits_set_to_one = 0;
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return FALSE;
}
for (size_t i = 0; i < m_nArraySizeBytes; i++)
{
BYTE b = m_pBitArray[i];
if (b == 0)
{
*bits_set_to_zero += 8;
}
else if (b == 0xFF)
{
*bits_set_to_one += 8;
}
else
{
// count bits by table lookup
static BYTE bittable[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4 };
// add count of bits in each nibble
size_t n = bittable[ (int) (b & 0x0F) ] +
bittable[ (int)((b & 0xF0) >> 4) ];
*bits_set_to_one += n;
*bits_set_to_zero += 8 - n;
}
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// Find()
//
// Purpose: Find next bit that has the value specified by bit_value
//
// Parameters: start_pos - bit number (0 - N); the search for a bit will
// start at this bit number. If necessary, the search
// will wrap to the beginning of the bit array.
// bit_value - value to look for (0 or 1)
// bit_pos - pointer to variable where bit number will be
// returned
//
// Returns: BOOL - TRUE = success
//
BOOL Find(size_t start_pos, BOOL bit_value, size_t *bit_pos) const
{
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return FALSE;
}
_ASSERTE(bit_pos);
if (!bit_pos)
{
XBITARRAY_TRACE(_T("ERROR: bad parameter\n"));
return FALSE;
}
*bit_pos = 0;
size_t byte_index, bit_index, bit_mask;
if (!GetBitPos(start_pos, &byte_index, &bit_index, &bit_mask))
return FALSE;
XBITARRAY_TRACE(_T("Find: start_pos=%d byte_index=%d bit_index=%d bit_mask=%02X\n"),
start_pos, byte_index, bit_index, bit_mask);
// advance starting point to ensure we look at all bits -
// the starting bit might have been in middle of byte
size_t start_byte_index = byte_index;
if (start_byte_index >= m_nArraySizeBytes)
start_byte_index = 0;
BOOL bFound = FALSE;
size_t nBitsScanned = 0; // keep track of number of bits scanned,
// to determine when to stop
size_t nBitsInByte = 8 - bit_index; // scan of starting byte might start
// in middle of byte
// loop thru all bytes in array
for (;;)
{
if (byte_index >= m_nArraySizeBytes)
{
// we have reached end of array, so continue at beginning
byte_index = 0;
XBITARRAY_TRACE(_T("starting at beginning - nBitsScanned=%d m_nArraySizeBits=%d\n"),
nBitsScanned, m_nArraySizeBits);
}
if (nBitsScanned >= m_nArraySizeBits)
{
// we have looked at all bytes --
// check if search has wrapped
if (byte_index == start_byte_index)
{
break;
}
}
// get next byte
BYTE b = m_pBitArray[byte_index];
XBITARRAY_TRACE(_T("b[%d]=%02X\n"), byte_index, b);
// NOTE: first (starting) byte might not start at bit 0
BYTE mask = (BYTE) bit_mask;
// loop thru all bits in byte - stop when
// high bit is reached
for (;;)
{
if (((b & mask) && bit_value) ||
(((b & mask) == 0) && !bit_value))
{
// found bit
// get bit no.
size_t index = GetBitNo(mask);
*bit_pos = byte_index * 8 + index;
bFound = TRUE;
break;
}
if (mask & 0x80) // done with byte if this was high bit
break;
mask = (BYTE) (mask << 1); // try next bit
} // for
if (bFound)
break;
bit_mask = 1; // start at bit 0 for next byte
byte_index++;
// keep track of bits scanned, so we know when to quit
nBitsScanned += nBitsInByte;
nBitsInByte = 8; // next byte will be full 8 bits
} // for
XBITARRAY_TRACE(_T("Find: bit_pos=%d returning %d\n"),
*bit_pos, bFound);
return bFound;
}
///////////////////////////////////////////////////////////////////////////////
//
// Get()
//
// Purpose: Get bit value at a bit index
//
// Parameters: pos - bit number (0 - N)
//
// Returns: BOOL - TRUE = bit is 1; FALSE = bit is 0
//
BOOL Get(size_t pos) const
{
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return 0;
}
size_t byte_index, bit_index, bit_mask;
if (GetBitPos(pos, &byte_index, &bit_index, &bit_mask))
{
return (m_pBitArray[byte_index] & bit_mask); // 0 or 1
}
else
{
return 0;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// GetArraySizeBits()
//
// Purpose: Get number of bits in bit array
//
// Parameters: None
//
// Returns: size_t - no. of bits in array
//
size_t GetArraySizeBits() const { return m_nArraySizeBits; }
///////////////////////////////////////////////////////////////////////////////
//
// GetArraySizeBytes()
//
// Purpose: Get size of bit array in bytes
//
// Parameters: None
//
// Returns: size_t - no. of bytes in array
//
size_t GetArraySizeBytes() const { return m_nArraySizeBytes; }
///////////////////////////////////////////////////////////////////////////////
//
// GetBitNo()
//
// Purpose: Convert bit mask to bit number
//
// Parameters: mask - mask of bit (00000001, 00000010, 00000100, etc.)
//
// Returns: size_t - bit number (0 - 7) within byte
//
size_t GetBitNo(BYTE mask) const
{
size_t index = 0;
while (mask != 1)
{
index++;
mask = (BYTE) (mask >> 1);
}
return index;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetBitPos()
//
// Purpose: Convert bit number to byte and bit indexes and bit mask
//
// Parameters: pos - bit number (0 - N)
// byte_index - index to byte in array
// bit_index - bit number within byte (0 - 7)
// bit_mask - mask of bit (00000001, 00000010, 00000100, etc.)
//
// Returns: BOOL - TRUE = success
//
BOOL GetBitPos(size_t pos,
size_t *byte_index,
size_t *bit_index,
size_t *bit_mask) const
{
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return FALSE;
}
*byte_index = pos / 8; // byte index [0-(N-1)] in array of size N bytes
*bit_index = pos % 8; // bit index [0-7] within the byte
*bit_mask = 1 << *bit_index; // bit mask
_ASSERTE(*byte_index < m_nArraySizeBytes);
if (*byte_index >= m_nArraySizeBytes)
{
XBITARRAY_TRACE(_T("ERROR: byte_index (%d) too large\n"), *byte_index);
*byte_index = 0;
return FALSE;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetPersistFileName()
//
// Purpose: Get persist file name
//
// Parameters: lpszPersistFile - pointer to file path buffer that receives the
// nul-terminated persist file path
// dwSize - size of buffer in TCHARs
//
// Returns: DWORD - length of string copied to lpszPersistFile in TCHARs
//
DWORD GetPersistFileName(LPTSTR lpszPersistFile, DWORD dwSize) const
{
_ASSERTE(lpszPersistFile);
if (lpszPersistFile == NULL)
return 0;
_ASSERTE(dwSize > 0);
if (dwSize < 2)
return 0;
memset(lpszPersistFile, 0, dwSize * sizeof(TCHAR));
_tcsncpy(lpszPersistFile, m_szPersistFile, dwSize-1);
return _tcslen(lpszPersistFile);
}
///////////////////////////////////////////////////////////////////////////////
//
// GetRegistryKeyName()
//
// Purpose: Get registry key name
//
// Parameters: lpszKeyName - pointer to buffer that receives the
// nul-terminated key name
// dwSize - size of buffer in TCHARs
//
// Returns: DWORD - length of string copied to lpszKeyName in TCHARs
//
DWORD GetRegistryKeyName(LPTSTR lpszKeyName, DWORD dwSize) const
{
_ASSERTE(lpszKeyName);
if (lpszKeyName == NULL)
return 0;
_ASSERTE(dwSize > 0);
if (dwSize < 2)
return 0;
memset(lpszKeyName, 0, dwSize * sizeof(TCHAR));
_tcsncpy(lpszKeyName, m_szKeyName, dwSize-1);
return _tcslen(lpszKeyName);
}
///////////////////////////////////////////////////////////////////////////////
//
// GetRegistryValueName()
//
// Purpose: Get registry value name
//
// Parameters: lpszValueName - pointer to buffer that receives the
// nul-terminated value name
// dwSize - size of buffer in TCHARs
//
// Returns: DWORD - length of string copied to lpszValueName in TCHARs
//
DWORD GetRegistryValueName(LPTSTR lpszValueName, DWORD dwSize) const
{
_ASSERTE(lpszValueName);
if (lpszValueName == NULL)
return 0;
_ASSERTE(dwSize > 0);
if (dwSize < 2)
return 0;
memset(lpszValueName, 0, dwSize * sizeof(TCHAR));
_tcsncpy(lpszValueName, m_szValueName, dwSize-1);
return _tcslen(lpszValueName);
}
///////////////////////////////////////////////////////////////////////////////
//
// operator []
//
// Purpose: Get bit value at a bit index
//
// Parameters: pos - bit number (0 - N)
//
// Returns: BOOL - TRUE = bit is 1; FALSE = bit is 0
//
BOOL operator [] (size_t pos) const
{
return Get(pos);
}
///////////////////////////////////////////////////////////////////////////////
//
// operator LPBYTE
//
// Purpose: Get address of bit array
//
// Parameters: None
//
// Returns: LPBYTE - address of bit array, or NULL
//
operator LPBYTE () const
{
return m_pBitArray;
}
///////////////////////////////////////////////////////////////////////////////
//
// Set()
//
// Purpose: Set bit value
//
// Parameters: pos - bit number (0 - N)
// bit_value - 0 or 1
//
// Returns: None
//
void Set(size_t pos, BOOL bit_value)
{
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return;
}
size_t byte_index, bit_index, bit_mask;
if (GetBitPos(pos, &byte_index, &bit_index, &bit_mask))
{
if (bit_value)
m_pBitArray[byte_index] |= bit_mask;
else
m_pBitArray[byte_index] &= ~(bit_mask);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// SetAll()
//
// Purpose: Set all bits to a value
//
// Parameters: bit_value - 0 or 1
//
// Returns: None
//
void SetAll(BOOL bit_value)
{
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return;
}
BYTE value = 0;
if (bit_value)
value = 0xFF;
for (size_t i = 0; i < m_nArraySizeBytes; i++)
m_pBitArray[i] = value;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetPersistFileName()
//
// Purpose: Set persist file name
//
// Parameters: lpszPersistFile - pointer to name of file containing bit array
//
// Returns: None
//
void SetPersistFileName(LPCTSTR lpszPersistFile)
{
memset(m_szPersistFile, 0, sizeof(m_szPersistFile));
if (lpszPersistFile)
_tcsncpy(m_szPersistFile, lpszPersistFile,
sizeof(m_szPersistFile)/sizeof(TCHAR)-2);
}
///////////////////////////////////////////////////////////////////////////////
//
// SetRegistryNames()
//
// Purpose: Set registry key and value names
//
// Parameters: lpszKeyName - key name
// lpszValueName - value name
//
// Returns: None
//
void SetRegistryNames(LPCTSTR lpszKeyName, LPCTSTR lpszValueName)
{
memset(m_szKeyName, 0, sizeof(m_szKeyName));
if (lpszKeyName)
_tcsncpy(m_szKeyName, lpszKeyName,
sizeof(m_szKeyName)/sizeof(TCHAR)-2);
memset(m_szValueName, 0, sizeof(m_szValueName));
if (lpszValueName)
_tcsncpy(m_szValueName, lpszValueName,
sizeof(m_szValueName)/sizeof(TCHAR)-2);
}
///////////////////////////////////////////////////////////////////////////////
//
// ToString()
//
// Purpose: Returns a string that represents the bit array
//
// Parameters: None
//
// Returns: LPTSTR - pointer to a string that has been allocated on the
// heap and must be freed by caller. The string
// contains one TCHAR for each bit in the array, plus
// a trailing nul. Returns NULL if failure.
//
LPTSTR ToString() const
{
LPTSTR s = NULL;
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
}
else
{
s = new TCHAR [m_nArraySizeBits + 1];
_ASSERTE(s);
if (s)
{
size_t i = 0;
for (i = 0; i < m_nArraySizeBits; i++)
{
if (Get(i))
s[i] = _T('1');
else
s[i] = _T('0');
}
s[i] = _T('\0');
}
}
return s;
}
// Operations
public:
///////////////////////////////////////////////////////////////////////////////
//
// ReadPersistFile()
//
// Purpose: Read bit array from file
//
// Parameters: lpszFile - name of file to read bit array from
// nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
// if it cannot be read from file
//
// Returns: BOOL - TRUE = success
//
// Notes: See Notes for CXBitArray #4. Whatever bit array address that
// is currently stored in m_pBitAddress will be replaced with a
// new address that is allocated from the heap, sized to hold the
// contents of the file. If the file cannot be read, the bit
// array will be allocated to hold (nArraySizeBits+7)/8 bytes,
// and initialized to bit_value.
//
BOOL ReadPersistFile(LPCTSTR lpszFile, size_t nArraySizeBits, BOOL bit_value)
{
XBITARRAY_TRACE(_T("in ReadPersistFile: %s\n"), lpszFile);
BOOL bSuccess = FALSE;
if (m_bDeleteArray && m_pBitArray)
delete [] m_pBitArray;
m_pBitArray = NULL;
m_bDeleteArray = FALSE;
_ASSERTE(lpszFile);
_ASSERTE(lpszFile[0] != _T('\0'));
if (!lpszFile || lpszFile[0] == _T('\0'))
{
XBITARRAY_TRACE(_T("ERROR: lpszFile is NULL\n"));
}
else
{
if (_taccess(lpszFile, 04) == 0)
{
// file exists, try to open it
HANDLE hFile = INVALID_HANDLE_VALUE;
hFile = ::CreateFile(lpszFile,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
XBITARRAY_TRACE(_T("ERROR: CreateFile failed for %s\n"),
lpszFile);
}
else
{
DWORD dwFileSize = ::GetFileSize(hFile, NULL);
if ((dwFileSize != INVALID_FILE_SIZE) && (dwFileSize > 0))
{
m_nArraySizeBytes = dwFileSize;
m_nArraySizeBits = 8 * m_nArraySizeBytes;
XBITARRAY_TRACE(_T("ReadPersistFile: allocating bit array for %d bytes\n"),
m_nArraySizeBytes);
m_pBitArray = new BYTE [m_nArraySizeBytes];
_ASSERTE(m_pBitArray);
if (m_pBitArray)
{
m_bDeleteArray = TRUE;
DWORD dwBytesRead = 0;
BOOL bRet = ::ReadFile(hFile,
(LPVOID) m_pBitArray,
dwFileSize,
&dwBytesRead,
NULL);
XBITARRAY_TRACE(_T("read %d bytes\n"), dwBytesRead);
if (bRet)
bSuccess = TRUE;
}
}
::CloseHandle(hFile);
}
}
else
{
XBITARRAY_TRACE(_T("ERROR: cannot open %s\n"),
lpszFile);
}
}
if (!bSuccess)
{
// allocate bit array and fill with default value
if (m_pBitArray == NULL)
{
m_nArraySizeBits = nArraySizeBits;
if (m_nArraySizeBits == 0)
m_nArraySizeBits = 1;
m_nArraySizeBytes = (m_nArraySizeBits + 7) / 8;
m_nArraySizeBits = m_nArraySizeBytes * 8;
XBITARRAY_TRACE(_T("ReadPersistFile: allocating bit array for %d bytes\n"),
m_nArraySizeBytes);
m_pBitArray = new BYTE [m_nArraySizeBytes];
_ASSERTE(m_pBitArray);
}
if (m_pBitArray)
{
m_bDeleteArray = TRUE;
SetAll(bit_value);
}
}
return bSuccess;
}
///////////////////////////////////////////////////////////////////////////////
//
// ReadRegistry()
//
// Purpose: Read bit array from registry
//
// Parameters: lpszKeyName - key name
// lpszValueName - value name
// nArraySizeBits - size of array in bits
// bit_value - bit array will be initialized to this value
// if it cannot be read from registry
//
// Returns: BOOL - TRUE = success
//
// Notes: See Notes for CXBitArray #5. Whatever bit array address that
// is currently stored in m_pBitAddress will be replaced with a
// new address that is allocated from the heap, sized to hold the
// contents of the registry value. If the registry cannot be read,
// the bit array will be allocated to hold (nArraySizeBits+7)/8
// bytes, and initialized to bit_value.
//
BOOL ReadRegistry(LPCTSTR lpszKeyName,
LPCTSTR lpszValueName,
size_t nArraySizeBits,
BOOL bit_value)
{
XBITARRAY_TRACE(_T("in ReadRegistry: %s\n"), lpszKeyName);
BOOL bSuccess = FALSE;
if (m_bDeleteArray && m_pBitArray)
delete [] m_pBitArray;
m_pBitArray = NULL;
m_bDeleteArray = FALSE;
_ASSERTE(lpszKeyName);
_ASSERTE(lpszKeyName[0] != _T('\0'));
if (!lpszKeyName || lpszKeyName[0] == _T('\0'))
{
XBITARRAY_TRACE(_T("ERROR: lpszKeyName is NULL\n"));
}
else
{
// open the registry key
XBITARRAY_TRACE(_T("trying to open key\n"));
HKEY hKey = NULL;
LONG lRet = ::RegOpenKeyEx(HKEY_CURRENT_USER, lpszKeyName, 0, KEY_READ, &hKey);
if (lRet == ERROR_SUCCESS)
{
// registry key was opened
XBITARRAY_TRACE(_T("key opened ok\n"));
// read value
DWORD dwType = 0;
DWORD dwSize = 0;
// get size of data in registry
lRet = ::RegQueryValueEx(hKey, lpszValueName, 0, &dwType, NULL, &dwSize);
XBITARRAY_TRACE(_T("dwSize=%d\n"), dwSize);
if (lRet == ERROR_SUCCESS)
{
// we now have size of data
m_nArraySizeBytes = dwSize;
m_nArraySizeBits = 8 * m_nArraySizeBytes;
XBITARRAY_TRACE(_T("ReadRegistry: allocating bit array for %d bytes\n"),
m_nArraySizeBytes);
m_pBitArray = new BYTE [m_nArraySizeBytes];
_ASSERTE(m_pBitArray);
if (m_pBitArray)
{
m_bDeleteArray = TRUE;
// read data from registry into bit array
lRet = ::RegQueryValueEx(hKey, lpszValueName, 0, &dwType,
m_pBitArray, &dwSize);
if (lRet == ERROR_SUCCESS)
bSuccess = TRUE;
}
}
::RegCloseKey(hKey);
}
}
if (!bSuccess)
{
XBITARRAY_TRACE(_T("registry read failed\n"));
// allocate bit array and fill with default value
if (m_pBitArray == NULL)
{
m_nArraySizeBits = nArraySizeBits;
if (m_nArraySizeBits == 0)
m_nArraySizeBits = 1;
m_nArraySizeBytes = (m_nArraySizeBits + 7) / 8;
m_nArraySizeBits = m_nArraySizeBytes * 8;
XBITARRAY_TRACE(_T("ReadRegistry: allocating bit array for %d bytes\n"),
m_nArraySizeBytes);
m_pBitArray = new BYTE [m_nArraySizeBytes];
_ASSERTE(m_pBitArray);
}
if (m_pBitArray)
{
m_bDeleteArray = TRUE;
SetAll(bit_value);
}
}
return bSuccess;
}
///////////////////////////////////////////////////////////////////////////////
//
// WritePersistFile()
//
// Purpose: Write bit array to file
//
// Parameters: lpszFile - name of file to write bit array to
//
// Returns: BOOL - TRUE = success
//
// Notes: See Notes for CXBitArray #4.
//
BOOL WritePersistFile(LPCTSTR lpszFile) const
{
XBITARRAY_TRACE(_T("in WritePersistFile: %s\n"), lpszFile);
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return FALSE;
}
BOOL bSuccess = FALSE;
_ASSERTE(lpszFile);
_ASSERTE(lpszFile[0] != _T('\0'));
if (!lpszFile || lpszFile[0] == _T('\0'))
{
XBITARRAY_TRACE(_T("ERROR: lpszFile is NULL\n"));
}
else
{
HANDLE hFile = INVALID_HANDLE_VALUE;
hFile = ::CreateFile(lpszFile,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
XBITARRAY_TRACE(_T("ERROR: CreateFile failed for %s\n"),
lpszFile);
}
else
{
DWORD dwBytesWritten = 0;
BOOL bRet = ::WriteFile(hFile,
(LPVOID) m_pBitArray,
m_nArraySizeBytes,
&dwBytesWritten,
NULL);
if (bRet)
{
::FlushFileBuffers(hFile);
bSuccess = TRUE;
}
::CloseHandle(hFile);
}
}
return bSuccess;
}
///////////////////////////////////////////////////////////////////////////////
//
// WriteRegistry()
//
// Purpose: Write bit array to registry
//
// Parameters: lpszKeyName - key name
// : lpszValueName - value name
//
// Returns: BOOL - TRUE = success
//
// Notes: See Notes for CXBitArray #5.
//
BOOL WriteRegistry(LPCTSTR lpszKeyName,
LPCTSTR lpszValueName) const
{
XBITARRAY_TRACE(_T("in WriteRegistry: %s\n"), lpszKeyName);
_ASSERTE((m_pBitArray != NULL) && (m_nArraySizeBytes != 0));
if ((m_pBitArray == NULL) || (m_nArraySizeBytes == 0))
{
XBITARRAY_TRACE(_T("ERROR: bit array not initialized\n"));
return FALSE;
}
BOOL bSuccess = FALSE;
_ASSERTE(lpszKeyName);
_ASSERTE(lpszKeyName[0] != _T('\0'));
if (!lpszKeyName || lpszKeyName[0] == _T('\0'))
{
XBITARRAY_TRACE(_T("ERROR: lpszKeyName is NULL\n"));
}
else
{
// open the registry key
DWORD dwResult = 0;
HKEY hKey = NULL;
LONG lRet = ::RegCreateKeyEx(HKEY_CURRENT_USER, lpszKeyName, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwResult);
if (lRet == ERROR_SUCCESS)
{
// registry key was opened or created
lRet = ::RegSetValueEx(hKey, lpszValueName, 0, REG_BINARY,
m_pBitArray, m_nArraySizeBytes);
if (lRet == ERROR_SUCCESS)
{
bSuccess = TRUE;
}
else
{
XBITARRAY_TRACE(_T("ERROR: RegSetValueEx failed\n"));
}
::RegCloseKey(hKey);
}
else
{
XBITARRAY_TRACE(_T("ERROR: RegCreateKeyEx failed\n"));
}
}
if (!bSuccess)
{
XBITARRAY_TRACE(_T("ERROR: WriteRegistry failed\n"));
}
return bSuccess;
}
// Implementation
private:
TCHAR m_szPersistFile[_MAX_PATH*2]; // persist file path
TCHAR m_szKeyName[_MAX_PATH*2]; // registry key name
TCHAR m_szValueName[_MAX_PATH*2]; // registry value name
BOOL m_bDeleteArray; // TRUE = delete array in dtor
BYTE * m_pBitArray; // pointer to bit array
size_t m_nArraySizeBytes; // no. of bytes in array
size_t m_nArraySizeBits; // no. of bits in array (always
// a multiple of 8)
};
#pragma warning(pop)
#endif //XBITARRAY_H