/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* hArray.cpp Index manager for TAPI devices db FILE HISTORY: Dec 16 1997 EricDav Created */ #include "stdafx.h" #include "harray.h" #include "mbstring.h" LPBYTE g_pStart; /*!-------------------------------------------------------------------------- Class CHDeviceIndex ---------------------------------------------------------------------------*/ CHDeviceIndex::CHDeviceIndex(INDEX_TYPE IndexType) : m_dbType(IndexType), m_bAscending(TRUE) { } CHDeviceIndex::~CHDeviceIndex() { } /*!-------------------------------------------------------------------------- CHDeviceIndex::GetType - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CHDeviceIndex::GetType(INDEX_TYPE * pIndexType) { if (pIndexType) *pIndexType = m_dbType; return hrOK; } /*!-------------------------------------------------------------------------- CHDeviceIndex::SetArray - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CHDeviceIndex::SetArray(HDeviceArray & hdeviceArray) { m_hdeviceArray.Copy(hdeviceArray); return hrOK; } /*!-------------------------------------------------------------------------- CHDeviceIndex::GetHDevice - Author: EricDav ---------------------------------------------------------------------------*/ HDEVICE CHDeviceIndex::GetHDevice(int nIndex) { Assert(nIndex >= 0); Assert(nIndex <= m_hdeviceArray.GetSize()); if (nIndex < 0 || nIndex >= m_hdeviceArray.GetSize()) { return NULL; } return m_hdeviceArray.GetAt(nIndex); } /*!-------------------------------------------------------------------------- CHDeviceIndex::GetIndex - Author: EricDav ---------------------------------------------------------------------------*/ int CHDeviceIndex::GetIndex(HDEVICE hdevice) { Assert(hdevice != 0); LPHDEVICE phdevice = (LPHDEVICE) BSearch((const void *)&hdevice, (const void *)m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE)); int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData()); Assert(nIndex >= 0); Assert(nIndex <= m_hdeviceArray.GetSize()); int nComp, nIndexTemp; nComp = BCompare(&hdevice, phdevice); if (nComp == 0) { // found the right one, check the previous one to return the first // record in a list of duplicates nIndexTemp = nIndex; while (nIndexTemp && nComp == 0) { *phdevice = m_hdeviceArray.GetAt(--nIndexTemp); nComp = BCompare(&hdevice, phdevice); } if (nIndexTemp == nIndex) return nIndex; // nIndex should be zero here as well else if (nComp == 0) return nIndexTemp; // nIndexTemp should be 0 in this case else return nIndexTemp++; } return -1; } /*!-------------------------------------------------------------------------- CHDeviceIndex::Add - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CHDeviceIndex::Add(HDEVICE hdevice, BOOL bEnd) { // if we are loading the array then just stick this on the end if (bEnd) { m_hdeviceArray.Add(hdevice); } else { if (m_hdeviceArray.GetSize() == 0) { m_hdeviceArray.Add(hdevice); } else { LPHDEVICE phdevice = (LPHDEVICE) BSearch((const void *)&hdevice, (const void *)m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE)); int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData()); Assert(nIndex >= 0); Assert(nIndex <= m_hdeviceArray.GetSize()); int nComp = BCompare(&hdevice, phdevice); if (nComp < 0) { if(nIndex == 0) m_hdeviceArray.InsertAt(nIndex , hdevice); else // Insert before phdevice m_hdeviceArray.InsertAt(nIndex - 1, hdevice); } else { // insert after phdevice m_hdeviceArray.InsertAt(nIndex + 1, hdevice); } } } return hrOK; } /*!-------------------------------------------------------------------------- CHDeviceIndex::Remove - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CHDeviceIndex::Remove(HDEVICE hdevice) { // do a bsearch for the record and then remove LPHDEVICE phdevice = (LPHDEVICE) BSearch(&hdevice, m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE)); int nComp = BCompare(&hdevice, phdevice); Assert(nComp == 0); if (nComp != 0) return E_FAIL; // calculate the index int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData()); Assert(nIndex >= 0); Assert(nIndex <= m_hdeviceArray.GetSize()); m_hdeviceArray.RemoveAt(nIndex); return hrOK; } /*!-------------------------------------------------------------------------- CHDeviceIndex::BSearch Modified bsearch which returns the closest or equal element in an array Author: EricDav ---------------------------------------------------------------------------*/ void * CHDeviceIndex::BSearch (const void *key, const void *base, size_t num, size_t width) { char *lo = (char *)base; char *hi = (char *)base + (num - 1) * width; char *mid; unsigned int half; int result; while (lo <= hi) if (half = num / 2) { mid = lo + (num & 1 ? half : (half - 1)) * width; if (!(result = BCompare(key,mid))) return(mid); else if (result < 0) { hi = mid - width; num = num & 1 ? half : half-1; } else { lo = mid + width; num = half; } } else if (num) return(lo); else break; return(mid); } /*!-------------------------------------------------------------------------- Class CIndexMgr ---------------------------------------------------------------------------*/ CIndexMgr::CIndexMgr() { m_posCurrentProvider= NULL; } CIndexMgr::~CIndexMgr() { Reset(); } /*!-------------------------------------------------------------------------- CIndexMgr::Initialize - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::Initialize() { HRESULT hr = hrOK; CSingleLock cl(&m_cs); cl.Lock(); COM_PROTECT_TRY { // cleanup Reset(); } COM_PROTECT_CATCH return hr; } /*!-------------------------------------------------------------------------- CIndexMgr::Reset - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::Reset() { CSingleLock cl(&m_cs); cl.Lock(); while (m_listProviderIndex.GetCount() > 0) { CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.RemoveHead(); while (pProviderIndexInfo->m_listIndicies.GetCount() > 0) delete pProviderIndexInfo->m_listIndicies.RemoveHead(); delete pProviderIndexInfo; } return hrOK; } /*!-------------------------------------------------------------------------- CIndexMgr::GetTotalCount The index sorted by name contains the total database and should always be available. Use this for the total count. Author: EricDav ---------------------------------------------------------------------------*/ UINT CIndexMgr::GetTotalCount() { CSingleLock cl(&m_cs); cl.Lock(); UINT uTotalCount = 0; POSITION pos; pos = m_listProviderIndex.GetHeadPosition(); while (pos) { CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetNext(pos); if (pProviderIndexInfo->m_listIndicies.GetCount() > 0) uTotalCount += (UINT)(pProviderIndexInfo->m_listIndicies.GetHead())->GetArray().GetSize(); } return uTotalCount; } /*!-------------------------------------------------------------------------- CIndexMgr::GetCurrentCount The current count may differ depending upon if the current Index is a filtered index. Author: EricDav ---------------------------------------------------------------------------*/ UINT CIndexMgr::GetCurrentCount() { CSingleLock cl(&m_cs); cl.Lock(); CProviderIndexInfo * pProviderIndexInfo = NULL; CHDeviceIndex * pIndex = NULL; pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex); if (pIndex == NULL) return 0; return (UINT)pIndex->GetArray().GetSize(); } /*!-------------------------------------------------------------------------- CIndexMgr::AddHDevice - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::AddHDevice(DWORD dwProviderID, HDEVICE hdevice, BOOL bEnd) { CSingleLock cl(&m_cs); cl.Lock(); HRESULT hr = hrOK; CProviderIndexInfo * pProviderIndexInfo = NULL; CHDeviceIndex * pIndex = NULL; COM_PROTECT_TRY { // set current provider set the current provider position and if // the provider doesn't exist, it will create one hr = SetCurrentProvider(dwProviderID); if (FAILED(hr)) return hr; pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex); if (pIndex) pIndex->Add(hdevice, bEnd); } COM_PROTECT_CATCH return hr; } /*!-------------------------------------------------------------------------- CIndexMgr::RemoveHDevice - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::RemoveHDevice(DWORD dwProviderID, HDEVICE hdevice) { CSingleLock cl(&m_cs); cl.Lock(); HRESULT hr = hrOK; CProviderIndexInfo * pProviderIndexInfo = NULL; CHDeviceIndex * pIndex = NULL; COM_PROTECT_TRY { hr = SetCurrentProvider(dwProviderID); if (FAILED(hr)) return hr; pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex); if (pIndex) pIndex->Remove(hdevice); } COM_PROTECT_CATCH return hr; } /*!-------------------------------------------------------------------------- CIndexMgr::Sort - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::Sort(DWORD dwProviderID, INDEX_TYPE SortType, DWORD dwSortOptions, LPBYTE pStart) { CSingleLock cl(&m_cs); cl.Lock(); HRESULT hr = hrOK; CHDeviceIndex * pNameIndex; CHDeviceIndex * pNewIndex; POSITION pos, posLast; INDEX_TYPE indexType; BOOL bAscending = (dwSortOptions & SORT_ASCENDING) ? TRUE : FALSE; hr = SetCurrentProvider(dwProviderID); if (FAILED(hr)) return hr; // check to see if we have an index for this. CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); pos = pProviderIndexInfo->m_listIndicies.GetHeadPosition(); while (pos) { posLast = pos; CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetNext(pos); pIndex->GetType(&indexType); // the index for this type already exists, just sort accordingly if (indexType == SortType) { if (pIndex->IsAscending() != bAscending) { pIndex->SetAscending(bAscending); pIndex->Sort(pStart); } pProviderIndexInfo->m_posCurrentIndex = posLast; return hrOK; } } // to save memory, remove all old indicies, except the name index //CleanupIndicies(); // if not, create one switch (SortType) { case INDEX_TYPE_NAME: pNewIndex = new CIndexName(); break; case INDEX_TYPE_USERS: pNewIndex = new CIndexUsers(); break; case INDEX_TYPE_STATUS: pNewIndex = new CIndexStatus(); break; default: Panic1("Invalid sort type passed to IndexMgr::Sort %d\n", SortType); break; } Assert(pNewIndex); // name index is always the first in the list pNameIndex = pProviderIndexInfo->m_listIndicies.GetHead(); Assert(pNameIndex); // copy the array from the named index pNewIndex->SetArray(pNameIndex->GetArray()); pNewIndex->SetAscending(bAscending); pNewIndex->Sort(pStart); pProviderIndexInfo->m_posCurrentIndex = pProviderIndexInfo->m_listIndicies.AddTail(pNewIndex); return hr; } /*!-------------------------------------------------------------------------- CIndexMgr::CleanupIndicies Removes all indicies except the name index, and a filtered view Author: EricDav ---------------------------------------------------------------------------*/ void CIndexMgr::CleanupIndicies() { CSingleLock cl(&m_cs); cl.Lock(); INDEX_TYPE indexType; CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); POSITION pos = pProviderIndexInfo->m_listIndicies.GetHeadPosition(); while (pos) { POSITION posLast = pos; CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetNext(pos); pIndex->GetType(&indexType); if (indexType == INDEX_TYPE_NAME) continue; pProviderIndexInfo->m_listIndicies.RemoveAt(posLast); delete pIndex; } } /*!-------------------------------------------------------------------------- CIndexMgr::GetHDevice Returns an hdevice based on an index into the current sorted list Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::GetHDevice(DWORD dwProviderID, int nIndex, LPHDEVICE phdevice) { CSingleLock cl(&m_cs); cl.Lock(); SetCurrentProvider(dwProviderID); CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex); Assert(pIndex); if (phdevice) *phdevice = pIndex->GetHDevice(nIndex); return hrOK; } /*!-------------------------------------------------------------------------- CIndexMgr::GetIndex Returns the index of an hlien from the current sorted list Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::GetIndex(DWORD dwProviderID, HDEVICE hdevice, int * pnIndex) { CSingleLock cl(&m_cs); cl.Lock(); SetCurrentProvider(dwProviderID); CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider); CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex); Assert(pIndex); if (pIndex) *pnIndex = pIndex->GetIndex(hdevice); return hrOK; } /*!-------------------------------------------------------------------------- CIndexMgr::SetCurrentProvider Sets the current provider for the index mgr, if it doesn't exist, it is created Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexMgr::SetCurrentProvider(DWORD dwProviderID) { HRESULT hr = hrOK; BOOL bExists = FALSE; POSITION posLast; COM_PROTECT_TRY { POSITION pos = m_listProviderIndex.GetHeadPosition(); while (pos) { posLast = pos; CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetNext(pos); // is the the correct provider to add this to? if (pProviderIndexInfo->m_dwProviderID != dwProviderID) continue; m_posCurrentProvider = posLast; bExists = TRUE; } if (!bExists) { // no provider index exists for this. Create one now. CProviderIndexInfo * pProviderIndexInfo = new CProviderIndexInfo; pProviderIndexInfo->m_dwProviderID = dwProviderID; CHDeviceIndex * pIndex = new CIndexName; pProviderIndexInfo->m_posCurrentIndex = pProviderIndexInfo->m_listIndicies.AddHead(pIndex); m_posCurrentProvider = m_listProviderIndex.AddTail(pProviderIndexInfo); } } COM_PROTECT_CATCH return hr; } /*!-------------------------------------------------------------------------- Class CIndexName ---------------------------------------------------------------------------*/ /*!-------------------------------------------------------------------------- CIndexName::BCompare - Author: EricDav ---------------------------------------------------------------------------*/ int CIndexName::BCompare(const void * elem1, const void * elem2) { int nRet; LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1; LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2; nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset)); if (nRet == 0) { // permanent device IDs should be unique if (pRec1->dwPermanentDeviceID > pRec2->dwPermanentDeviceID) nRet = 1; else nRet = -1; } return nRet; } /*!-------------------------------------------------------------------------- CIndexName::Sort - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexName::Sort(LPBYTE pStart) { // save the base pointer for later g_pStart = pStart; if (m_bAscending) qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA); else qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD); return hrOK; } /*!-------------------------------------------------------------------------- CIndexName::QCompare - Author: EricDav ---------------------------------------------------------------------------*/ int __cdecl CIndexName::QCompareA(const void * elem1, const void * elem2) { int nRet; LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1; LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2; nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset)); if (nRet == 0) { // permanent device IDs should be unique if (pRec1->dwPermanentDeviceID > pRec2->dwPermanentDeviceID) nRet = 1; else nRet = -1; } return nRet; } int __cdecl CIndexName::QCompareD(const void * elem1, const void * elem2) { return -QCompareA(elem1, elem2); } /*!-------------------------------------------------------------------------- Class CIndexUsers ---------------------------------------------------------------------------*/ /*!-------------------------------------------------------------------------- CIndexUsers::BCompare - Author: EricDav ---------------------------------------------------------------------------*/ int CIndexUsers::BCompare(const void * elem1, const void * elem2) { int nRet; LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1; LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2; nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDomainUserNamesOffset), (LPCTSTR) (g_pStart + pRec2->dwDomainUserNamesOffset)); if (nRet == 0) nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset)); return nRet; } /*!-------------------------------------------------------------------------- CIndexUsers::Sort - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexUsers::Sort(LPBYTE pStart) { // save the base pointer for later g_pStart = pStart; if (m_bAscending) qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA); else qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD); return hrOK; } /*!-------------------------------------------------------------------------- CIndexUsers::QCompare - Author: EricDav ---------------------------------------------------------------------------*/ int __cdecl CIndexUsers::QCompareA(const void * elem1, const void * elem2) { int nRet; LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1; LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2; nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDomainUserNamesOffset), (LPCTSTR) (g_pStart + pRec2->dwDomainUserNamesOffset)); if (nRet == 0) nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset)); return nRet; } int __cdecl CIndexUsers::QCompareD(const void * elem1, const void * elem2) { return -QCompareA(elem1, elem2); } /*!-------------------------------------------------------------------------- Class CIndexStatus ---------------------------------------------------------------------------*/ /*!-------------------------------------------------------------------------- CIndexStatus::BCompare - Author: EricDav ---------------------------------------------------------------------------*/ int CIndexStatus::BCompare(const void * elem1, const void * elem2) { LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1; LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2; //return _mbscmp((const PUCHAR) &pRec1->szRecordName[0], (const PUCHAR) &pRec2->szRecordName[0]); return 0; } /*!-------------------------------------------------------------------------- CIndexStatus::Sort - Author: EricDav ---------------------------------------------------------------------------*/ HRESULT CIndexStatus::Sort(LPBYTE pStart) { // save the base pointer for later g_pStart = pStart; if (m_bAscending) qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA); else qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD); return hrOK; } /*!-------------------------------------------------------------------------- CIndexIpAddr::QCompare - Author: EricDav ---------------------------------------------------------------------------*/ int __cdecl CIndexStatus::QCompareA(const void * elem1, const void * elem2) { LPHDEVICE phdevice1 = (LPHDEVICE) elem1; LPHDEVICE phdevice2 = (LPHDEVICE) elem2; LPHDEVICE pRec1 = (LPHDEVICE) *phdevice1; LPHDEVICE pRec2 = (LPHDEVICE) *phdevice2; //return lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset)); return 0; } int __cdecl CIndexStatus::QCompareD(const void * elem1, const void * elem2) { return -QCompareA(elem1, elem2); }