|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: umisrch.cxx
//
// Contents: This object wraps an IDirectorySearch and returns Umi objects
// as a result of the search. The Umi objects returned are
// pre-populated with the attributes received from the search.
// This object is used by the cursor object to support the
// IUmiCursor interface.
// This file also contains the CQueryStack helper class that is
// used by the SearcHelper to parse SQL queries.
//
// History: 03-20-00 AjayR Created.
//
//----------------------------------------------------------------------------
#include "ldap.hxx"
//
// Helper functions.
//
//+---------------------------------------------------------------------------
// Function: HelperGetAttributeList - helper routine.
//
// Synopsis: Gets a list of attributes that can be used in an execute
// search call from the wbem query information.
//
// Arguments: pdwAttribCount - Returns the number of attributes.
// -1 means all attributes.
// pppszAttribArray - Return value for string array.
// ulListSize - Size of list of wbem names.
// pWbemNames - The list of parsed tokens.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pdwAttribCount to correct value and pppszAttribArray to
// array of strings containing the attribute list.
//
//----------------------------------------------------------------------------
HRESULT HelperGetAttributeList( PDWORD pdwAttribCount, LPWSTR ** pppszAttribArray, ULONG ulListSize, SWbemQueryQualifiedName **pWbemNames ) { HRESULT hr = S_OK; DWORD dwCtr = 0; SWbemQueryQualifiedName *pName = NULL; LPWSTR pszTmpString = NULL;
//
// There should at least be a * in the list.
//
ADsAssert(pWbemNames);
*pppszAttribArray = NULL; *pdwAttribCount = (DWORD) -1;
//
// If the count is just one we need to see if this is just *.
//
if (ulListSize == 1) { pName = pWbemNames[0]; if (pName->m_ppszNameList && pName->m_ppszNameList[0] ) { if (_wcsicmp(pName->m_ppszNameList[0], L"*")) { //
// We need to retun NULL and -1 for count.
//
RRETURN(hr); } } else { //
// This has to be a bad query cause either
// 1) the name list was empty - cannot have empty from clause,
// 2) the name list had an empty string in it, or
//
BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY ???
} } //
// At this point we have a valid attribute list.
//
*pppszAttribArray = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * ulListSize); if (!*pppszAttribArray) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
for (dwCtr = 0; dwCtr < ulListSize; dwCtr++) { pszTmpString = NULL; pName = pWbemNames[dwCtr]; if (!pName || !pName->m_ppszNameList) { BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_BAD_QUERY ???
} //
// ADSI does not expect more than one entry in each of the pName's.
// so if some did user.Description then we just treat this as
// as description by using the last value always.
//
pszTmpString = AllocADsStr( pName->m_ppszNameList[pName->m_uNameListSize-1] );
if (!pszTmpString) { BAIL_ON_FAILURE(hr = E_FAIL); } (*pppszAttribArray)[dwCtr] = pszTmpString; }
*pdwAttribCount = ulListSize;
error:
if (FAILED(hr)) { if (*pppszAttribArray) { for (dwCtr = 0; dwCtr < ulListSize; dwCtr++) { pszTmpString = (*pppszAttribArray)[dwCtr]; if (pszTmpString) { FreeADsStr(pszTmpString); } } FreeADsMem(*pppszAttribArray); *pppszAttribArray = NULL; } }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: HelperGetFromList - helper routine.
//
// Synopsis: Get a filter that represents the from list. For now this
// will only return NULL. However we will need to spruce this fn
// if we need to support a list of classes in here.
//
// Arguments: ppszFromFilter - Return value for a filter corresponding
// to the From list.
// pQuery - Wbem query object.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: *ppszFromFilter if From list is valid.
//
//----------------------------------------------------------------------------
HRESULT HelperGetFromList( LPWSTR *ppszFromFilter, SWbemRpnEncodedQuery *pQuery ) { HRESULT hr = E_FAIL; LPWSTR pszFilter = NULL;
*ppszFromFilter = NULL;
if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_PATH) { //
// This can only be . for now.
//
if (!_wcsicmp(L".", pQuery->m_pszOptionalFromPath)) { //
// We are ok as long as there are no other pieces.
//
RRETURN(S_OK); } else { RRETURN(E_FAIL); // UMI_E_NOT_SUPPORTED ???
} }
//
// For now we are going to ignore pieces if there are any other
// pieces in the from clause.
//
if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_UNARY) { // hr = E_FAIL; UMI_E_NOT_SUPPORTED.
hr = S_OK; } else if (pQuery->m_uFromTargetType & WMIQ_RPN_FROM_CLASS_LIST) { // hr = E_FAIL; UMI_E_NOT_SUPPORTED.
//for (unsigned u = 0; u < pQuery->m_uFromListSize; u++)
//{
// printf(" Selected class = %S\n", pQuery->m_ppszFromList[u]);
//}
hr = S_OK; } else { //
// The query does not have anything in the from clause.
// This is an invalid query.
//
hr = E_FAIL; // UMI_E_NOT_SUPPORTED ???
}
RRETURN(hr); } //+---------------------------------------------------------------------------
// Function: HelperGetSubExpressionFromOperands - helper routine.
//
// Synopsis: Updates the result with the operands and the operator. This
// routine munges the operators/operands around so that we can
// support operands not supported by ldap directly.
//
// Arguments: pszResult - Return value, allocated by caller.
// pszOperand1 - The attribute being tested.
// pszOperand2 - The value being tested against.
// ulOperator - Inidcates the comparision type.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pStack contents.
//
//----------------------------------------------------------------------------
HRESULT HelperGetSubExpressionFromOperands( LPWSTR pszResult, LPWSTR pszOperand1, LPWSTR pszOperand2, ULONG ulOperator ) { HRESULT hr = S_OK;
//
// In all cases we will need to begin with "(".
//
wsprintf(pszResult, L"(");
//
// All these are easy to handle.
//
if ((ulOperator == WMIQ_RPN_OP_EQ) || (ulOperator == WMIQ_RPN_OP_LT) || (ulOperator == WMIQ_RPN_OP_GT) ) { wcscat(pszResult, pszOperand1); }
switch (ulOperator) { case WMIQ_RPN_OP_EQ : wcscat(pszResult, L"="); wcscat(pszResult, pszOperand2); wcscat(pszResult, L")"); break;
case WMIQ_RPN_OP_LT : wcscat(pszResult, L"<"); wcscat(pszResult, pszOperand2); wcscat(pszResult, L")"); break;
case WMIQ_RPN_OP_GT : wcscat(pszResult, L">"); wcscat(pszResult, pszOperand2); wcscat(pszResult, L")"); break;
//
// All these need some processing as ldap does not
// handle these directly.
//
case WMIQ_RPN_OP_NE : //
// This needs to be (!(operand1=operand2)) so a != b becomes
// (!(a=b))
//
wcscat(pszResult, L"!"); wcscat(pszResult, L"("); wcscat(pszResult, pszOperand1); wcscat(pszResult, L"="); wcscat(pszResult, pszOperand2); wcscat(pszResult, L"))"); break;
case WMIQ_RPN_OP_GE : //
// a >= b becomes (!(a<b))
//
wcscat(pszResult, L"!("); wcscat(pszResult, pszOperand1); wcscat(pszResult, L"<"); wcscat(pszResult, pszOperand2); wcscat(pszResult, L"))"); break;
case WMIQ_RPN_OP_LE : //
// a <= b becomes (!(a>b))
//
wcscat(pszResult, L"!("); wcscat(pszResult, pszOperand1); wcscat(pszResult, L">"); wcscat(pszResult, pszOperand2); wcscat(pszResult, L"))"); break;
default: hr = E_FAIL; // UMI_E_UNSUPPORTED_QUERY.
break; }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: HelperProcessOperator - helper routine.
//
// Synopsis: Pops 2 elements from the stack, applies the operator on them
// and pushes the effective expression on to the stack.
//
// Arguments: pStack - Valid stack which should have at least 2
// elements in the stack.
// ulOperatorType- Operator type corresponding to wbem enum.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pStack contents.
//
//----------------------------------------------------------------------------
HRESULT HelperProcessSubExpression( CQueryStack *pStack, SWbemRpnQueryToken *pExpression ) { HRESULT hr = S_OK; LPWSTR pszOperand1 = NULL; LPWSTR pszOperand2 = NULL; LPWSTR pszResult = NULL; ULONG ulShape = pExpression->m_uSubexpressionShape; DWORD dwTotalLen = 0;
ADsAssert(pStack);
//
// As per what is supported we should not have a function.
// However the query parses seems to always report functions so we
// will ignore.
//
if (ulShape & WMIQ_RPN_LEFT_PROPERTY_NAME) { SWbemQueryQualifiedName *pName = pExpression->m_pLeftIdent; //
// The identifier could be x.y.z in which case ADSI is only
// interested in z
//
if (pName->m_ppszNameList[pName->m_uNameListSize-1]) { //
// Alloc the name itself if the operand1 is not __CLASS.
// If it is __CLASS we need to substitute with objectClass.
//
if (!_wcsicmp( pName->m_ppszNameList[pName->m_uNameListSize-1], L"__CLASS" ) ) { pszOperand1 = AllocADsStr(L"objectClass"); } else { //
// Alloc whatever was passed in.
//
pszOperand1 = AllocADsStr( pName->m_ppszNameList[pName->m_uNameListSize-1] ); } if (!pszOperand1) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } else { //
// Something really wrong.
//
BAIL_ON_FAILURE(hr = E_FAIL); } } else { //
// We cannot handle this as there is no identifier on LHS.
//
BAIL_ON_FAILURE(hr = E_FAIL); }
//
// We should have the operand by now, need the value
//
switch (pExpression->m_uConstApparentType) { case VT_I4: case VT_UI4: //
// We cannot possibly have more than 20 chars.
//
pszOperand2 = (LPWSTR) AllocADsMem(20 * sizeof(WCHAR)); if (!pszOperand2) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } if (pExpression->m_uConstApparentType == VT_I4) { _ltot(pExpression->m_Const.m_lLongVal, pszOperand2, 10 ); } else { _ltot(pExpression->m_Const.m_uLongVal, pszOperand2, 10); } break;
case VT_BOOL: //
// Again 20 sounds good !
//
pszOperand2 = (LPWSTR) AllocADsMem(20 * sizeof(WCHAR)); if (!pszOperand2) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
if (pExpression->m_Const.m_bBoolVal ) wcscpy(pszOperand2, L"TRUE"); else wcscpy(pszOperand2, L"FALSE"); break;
case VT_LPWSTR: pszOperand2 = AllocADsStr(pExpression->m_Const.m_pszStrVal); if (!pszOperand2) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } break;
default: BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED.
break; }
//
// At this point we can combine the 2 operands and operator.
// Total size is size of strings + () + 2 for operator + 1 for \0.
// Total additions = 5. This is for most cases.
//
dwTotalLen = wcslen(pszOperand1) + wcslen(pszOperand2) + 5;
//
// Operators <= >= and != need to be processed to be usable in ldap.
// In these cases, we assume that twice the length is needed.
//
dwTotalLen *= 2;
pszResult = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR)); if (!pszResult) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
hr = HelperGetSubExpressionFromOperands( pszResult, pszOperand1, pszOperand2, pExpression->m_uOperator );
/*
wsprintf(pszResult, L"("); wcscat(pszResult, pszOperand1); //
// Need to add the opearator now.
//
switch (pExpression->m_uOperator) {
case WMIQ_RPN_OP_EQ : wcscat(pszResult,L"="); break;
case WMIQ_RPN_OP_NE : wcscat(pszResult, L"!="); break;
case WMIQ_RPN_OP_GE : wcscat(pszResult, L">="); break;
case WMIQ_RPN_OP_LE : wcscat(pszResult, L"<="); break;
case WMIQ_RPN_OP_LT : wcscat(pszResult, L"<"); break;
case WMIQ_RPN_OP_GT : wcscat(pszResult, L">"); break;
case WMIQ_RPN_OP_UNDEFINED: case WMIQ_RPN_OP_LIKE : case WMIQ_RPN_OP_ISA : case WMIQ_RPN_OP_ISNOTA : default : //
// All these mean we have a bad query.
//
BAIL_ON_FAILURE(hr = E_FAIL); break; }
//
// Now tag on operand2 and the closing ), and push result onto stack.
//
wcscat(pszResult, pszOperand2); wcscat(pszResult, L")"); */
hr = pStack->Push(pszResult, QUERY_STACK_ITEM_LITERAL); BAIL_ON_FAILURE(hr); error:
if (pszOperand1) { FreeADsStr(pszOperand1); }
if (pszOperand2) { FreeADsStr(pszOperand2); }
if (pszResult) { FreeADsStr(pszResult); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: HelperProcessOperator - helper routine.
//
// Synopsis: Pops 2 elements from the stack, applies the operator on them
// and pushes the effective expression on to the stack.
//
// Arguments: pStack - Valid stack which should have at least 2
// elements in the stack.
// ulOperatorType- Operator type corresponding to wbem enum.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: pStack contents.
//
//----------------------------------------------------------------------------
HRESULT HelperProcessOperator( CQueryStack *pStack, ULONG ulOperatorType ) { HRESULT hr; LPWSTR pszStr1 = NULL; LPWSTR pszStr2 = NULL; LPWSTR pszResult = NULL; DWORD dwNodeType; DWORD dwTotalLen = 0;
ADsAssert(pStack);
hr = pStack->Pop( &pszStr1, &dwNodeType ); BAIL_ON_FAILURE(hr);
//
// String has to be valid and the node cannot be an operator.
//
if (!pszStr1 || !*pszStr1 || (dwNodeType != QUERY_STACK_ITEM_LITERAL) ) { BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
}
dwTotalLen += wcslen(pszStr1); //
// Not has only one operand.
//
if (ulOperatorType != WMIQ_RPN_TOKEN_NOT) { hr = pStack->Pop( &pszStr2, &dwNodeType ); BAIL_ON_FAILURE(hr);
//
// Sanity check.
//
if (!pszStr2 || !*pszStr2 || (dwNodeType != QUERY_STACK_ITEM_LITERAL) ) { BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
} //
// Need to add string2's length.
//
dwTotalLen += wcslen(pszStr2); }
//
// The resultant node needs to hold both strings and the operator
// and the additional set of parentheses.
// 4 = operator + () and one for \0.
//
dwTotalLen += 4; pszResult = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR)); if (!pszResult) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
wsprintf(pszResult, L"("); switch (ulOperatorType) { case WMIQ_RPN_TOKEN_AND : wcscat(pszResult, L"&"); break;
case WMIQ_RPN_TOKEN_OR : wcscat(pszResult, L"|"); break;
case WMIQ_RPN_TOKEN_NOT : wcscat(pszResult, L"!"); break;
default: BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED.
}
//
// At this point we need to tag on both the pre composed pieces
// and the final closing parentheses.
//
wcscat(pszResult, pszStr1); //
// Do not Tag on the second string only if operator is NOT.
//
if (ulOperatorType != WMIQ_RPN_TOKEN_NOT) { wcscat(pszResult, pszStr2); }
wcscat(pszResult, L")");
//
// Need to push the result on to the stack as a literal.
//
hr = pStack->Push( pszResult, QUERY_STACK_ITEM_LITERAL ); BAIL_ON_FAILURE(hr);
error:
if (pszStr1) { FreeADsStr(pszStr1); }
if (pszStr2) { FreeADsStr(pszStr2); }
if (pszResult) { FreeADsStr(pszResult); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: HelperGetFilterFromWhereClause - helper routine.
//
// Synopsis: Returns a filter corresponding to the elements specified in
// the where clause.
//
// Arguments: ppszFilter - Return value for a filter corresponding
// to the Where clause.
// ulCount - Number of elements in the where clause.
// pWhere - Pointer to the Wbem where clause.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: *ppszFilter if Where clause is valid.
//
//----------------------------------------------------------------------------
HRESULT HelperGetFilterFromWhereClause( LPWSTR *ppszFilter, ULONG ulCount, SWbemRpnQueryToken **pWhere ) { HRESULT hr = S_OK; DWORD dwCtr; CQueryStack *pStack = NULL; LPWSTR pszFilter = NULL; DWORD dwType;
*ppszFilter = NULL;
if (!ulCount) { //
// In this case we will default to NULL.
//
RRETURN(hr); }
pStack = new CQueryStack(); if (!pStack) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
//
// Process the tokens in the where clause.
//
for (dwCtr = 0; dwCtr < ulCount; dwCtr++) { SWbemRpnQueryToken *pToken = pWhere[dwCtr];
switch (pToken->m_uTokenType) { //
// All these are operations.
//
case WMIQ_RPN_TOKEN_AND : case WMIQ_RPN_TOKEN_OR : case WMIQ_RPN_TOKEN_NOT : HelperProcessOperator(pStack, pToken->m_uTokenType); break;
case WMIQ_RPN_TOKEN_EXPRESSION : HelperProcessSubExpression(pStack, pToken); break;
default: //
// We cannot handle the query.
//
hr = E_FAIL; // UMI_E_UNSUPPORTED_QUERY.
break; } BAIL_ON_FAILURE(hr); }
//
// At this stack should have one element and that should be
// the filter we use if things went right.
//
hr = pStack->Pop( &pszFilter, &dwType ); BAIL_ON_FAILURE(hr);
if (!pStack->IsEmpty()) { BAIL_ON_FAILURE(hr = E_FAIL); // UMI_E_UNSUPPORTED_QUERY
}
*ppszFilter = pszFilter;
error:
if (pStack) { delete pStack; }
if (FAILED(hr) && pszFilter) { FreeADsStr(pszFilter); }
RRETURN(hr); }
HRESULT HelperGetSortKey( SWbemRpnEncodedQuery *pRpn, PADS_SORTKEY * ppADsSortKey ) { HRESULT hr = S_OK; PADS_SORTKEY pSortKey = NULL;
if (!pRpn->m_uOrderByListSize) { RRETURN(S_OK); } //
// Allocate the sort key.
//
pSortKey = (PADS_SORTKEY) AllocADsMem(sizeof(ADS_SORTKEY)); if (!pSortKey) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
pSortKey->pszAttrType = AllocADsStr(pRpn->m_ppszOrderByList[0]); if (!pSortKey->pszAttrType) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
if (pRpn->m_uOrderDirectionEl[0]) { pSortKey->fReverseorder = TRUE; }
RRETURN(S_OK); error:
if (pSortKey) { if (pSortKey->pszAttrType) { FreeADsStr(pSortKey->pszAttrType); } FreeADsMem(pSortKey); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::CUmiSearchHelper --- Constructor.
//
// Synopsis: Standard constructor.
//
// Arguments: N/A.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
CUmiSearchHelper::CUmiSearchHelper(): _hSearchHandle(NULL), _pConnection(NULL), _pContainer(NULL), _pszADsPath(NULL), _pszLdapServer(NULL), _pszLdapDn(NULL), _pIID(NULL), _fSearchExecuted(FALSE), _fResetAllowed(TRUE) { //
// This is global scope helper routine that will not fail.
// The boolean is the value for cache results.
//
LdapInitializeSearchPreferences(&_searchPrefs, FALSE); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::~CUmiSearchHelper --- Destructor.
//
// Synopsis: Standard destructor.
//
// Arguments: N/A.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
CUmiSearchHelper::~CUmiSearchHelper() { if (_hSearchHandle) { ADsCloseSearchHandle(_hSearchHandle); }
if (_pConnection) { _pConnection->Release(); }
if (_pContainer) { _pContainer->Release(); }
if (_pQuery) { _pQuery->Release(); }
if (_pszADsPath) { FreeADsStr(_pszADsPath); }
if (_pszLdapServer) { FreeADsStr(_pszLdapServer); }
if (_pszLdapDn) { FreeADsStr(_pszLdapDn); }
if (_pCreds) { delete _pCreds; }
}
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::CreateSearchHelper --- STATIC constructor.
//
// Synopsis: Static constructor.
//
// Arguments: pUmiQuery - Pointer to query object that.
// pConnection - Connection to execute query on.
// pUnk - Container on which the query is executed.
// pSrchObj - New object is returned in this param.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::CreateSearchHelper( IUmiQuery *pUmiQuery, IUmiConnection *pConnection, IUnknown *pUnk, LPCWSTR pszADsPath, LPCWSTR pszLdapServer, LPCWSTR pszLdapDn, CCredentials cCredentials, DWORD dwPort, CUmiSearchHelper FAR* FAR * ppSrchObj ) { HRESULT hr = S_OK; CUmiSearchHelper FAR * pSearchHelper = NULL; //
// Asserts are good enough as this is an internal routine.
//
ADsAssert(ppSrchObj); ADsAssert(pUmiQuery && pConnection && pUnk);
pSearchHelper = new CUmiSearchHelper(); if (!pSearchHelper) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
pSearchHelper->_pszADsPath = AllocADsStr(pszADsPath); if (!pSearchHelper->_pszADsPath) { BAIL_ON_FAILURE(hr); }
//
// pszLdapDn can be null
//
if (pszLdapDn) { pSearchHelper->_pszLdapDn = AllocADsStr(pszLdapDn); if (!pSearchHelper->_pszLdapDn) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } //
// the server can also be null.
//
if (pszLdapServer) { pSearchHelper->_pszLdapServer = AllocADsStr(pszLdapServer); if (!pSearchHelper->_pszLdapServer) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } }
pSearchHelper->_pCreds = new CCredentials(cCredentials); if (!pSearchHelper->_pCreds) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
pSearchHelper->_pConnection = pConnection; pConnection->AddRef();
pSearchHelper->_pQuery = pUmiQuery; pUmiQuery->AddRef();
pSearchHelper->_pContainer = pUnk; pUnk->AddRef();
pSearchHelper->_dwPort = dwPort;
*ppSrchObj = (CUmiSearchHelper FAR *)pSearchHelper; RRETURN(hr);
error :
delete pSearchHelper; RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::SetIID
//
// Synopsis: Sets the IID requested on the returned objects.
//
// Arguments: riid - The iid requested.
//
// Returns: S_OK or any appropriate error code.
//
// Modifies: _pIID the internal IID pointer.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::SetIID(REFIID riid) { if (_pIID) { FreeADsMem(_pIID); }
_pIID = (IID *) AllocADsMem(sizeof(IID));
if (!_pIID) { RRETURN(E_OUTOFMEMORY); }
memcpy(_pIID, &riid, sizeof(IID));
RRETURN(S_OK); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::Reset
//
// Synopsis: Not implemented.
//
// Arguments: None.
//
// Returns: E_NOTIMPL.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::Reset() { //
// We can potentially add support for this down the road.
//
RRETURN(E_NOTIMPL); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::Next
//
// Synopsis: Return the next uNumRequested elements from the search.
//
// Arguments: uNumRequested - number of objects/rows to fetch.
// pNumReturned - number of objects/rows returned.
// pObject - array of returned objects.
//
// Returns: S_OK, S_FALSE or any appropriate error code.
//
// Modifies: pNumReturned, pObjects and internal search handle state.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::Next( ULONG uNumRequested, ULONG *puNumReturned, LPVOID *ppObjects ) { HRESULT hr = S_OK; IUnknown **pTempUnks = NULL; DWORD dwCtr = 0, dwIndex = 0;
if (!puNumReturned || !ppObjects || (uNumRequested < 1)) { BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER); }
if (!_fSearchExecuted) { hr = InitializeSearchContext(); BAIL_ON_FAILURE(hr); }
pTempUnks = (IUnknown **) AllocADsMem(sizeof(IUnknown*) * uNumRequested); if (!pTempUnks) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
//
// Get the requested number of objects one at a time until
// we hit S_FALSE or an error and then repackage to suitable
// array as needed.
//
while ((dwCtr < uNumRequested) && (hr != S_FALSE) ) { IUnknown *pUnk = NULL; hr = GetNextObject(&pUnk); //
// This wont catch S_FALSE.
//
BAIL_ON_FAILURE(hr); //
// Needed as if he get S_FALSE we will set the ptr and
// increase the count incorrectly.
//
if (hr != S_FALSE) { pTempUnks[dwCtr] = pUnk; dwCtr++; } }
//
// At this point we have all the results we need or can get.
//
if (uNumRequested == dwCtr) { //
// We can return tempObjects in this case.
//
*ppObjects = (void *)pTempUnks; } else { //
// Less than what had been requested.
//
IUnknown **pUnkCopy; pUnkCopy = (IUnknown **) AllocADsMem(sizeof(IUnknown *) * dwCtr); if (!pUnkCopy) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
for (dwIndex = 0; dwIndex < dwCtr; dwIndex++) { //
// Just need to copy the ptrs over.
//
pUnkCopy[dwIndex] = pTempUnks[dwIndex]; }
//
// Only return the number of entries we got back.
//
*ppObjects = (void *) pUnkCopy;
FreeADsMem((void *)pTempUnks); }
//
// We are error free over here.
//
*puNumReturned = dwCtr; RRETURN(hr);
error:
if (pTempUnks) { //
// For will be executed only if we have valid count.
//
for (dwIndex = 0; dwIndex < dwCtr; dwIndex++) { pTempUnks[dwIndex]->Release(); }
FreeADsMem(pTempUnks); }
*puNumReturned = 0;
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::Previous (E_NOTIMPL)
//
// Synopsis: Return the previous object in the result set - Not implemented.
//
// Arguments: uFlags - only flag supported is 0.
// pObj - object is returned in this param.
//
// Returns: S_OK, or any appropriate error code.
//
// Modifies: Internal search handle state and pObject.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::Previous( ULONG uFlags, LPVOID *pObj ) { RRETURN(E_NOTIMPL); }
//
// Internal/protected routines
//
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::InitializeSearchContext.
//
// Synopsis: Prepares the internal state of the object. This initializes
// the search preferences from the query object, leaveing the search
// helper ready to retrieve results.
//
// Arguments: None.
//
// Returns: S_OK, or any appropriate error code.
//
// Modifies: Internal search preferences and also state search handle.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::InitializeSearchContext() { HRESULT hr = S_OK; PUMI_PROPERTY_VALUES pPropVals = NULL; IUmiPropList *pPropList = NULL; LPWSTR pszFilter = NULL; LPWSTR *pszAttrNames = NULL; DWORD dwAttrCount = (DWORD) -1; ULONG ulLangBufSize = 100 * sizeof(WCHAR); ULONG ulQueryBufSize = 1024 * sizeof(WCHAR); LPWSTR pszLangBuf = NULL; LPWSTR pszQueryText = NULL; PADS_SORTKEY pSortKey = NULL;
//
// We need to walk through the properties in the query and update
// our local copy of preferences accordingly.
//
if (!_pQuery) { BAIL_ON_FAILURE(hr = E_FAIL); }
hr = _pQuery->GetInterfacePropList(0, &pPropList); BAIL_ON_FAILURE(hr);
//
// Need to allocate memory for the buffers.
//
pszLangBuf = (LPWSTR) AllocADsMem(ulLangBufSize); pszQueryText = (LPWSTR) AllocADsMem(ulQueryBufSize); if (!pszLangBuf || !pszQueryText) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } //
// We need to look at the query language if the language is SQL,
// then we need to go through and convert the SQL settings to
// properties on the intfPropList of the query.
//
hr = _pQuery->GetQuery( &ulLangBufSize, pszLangBuf, &ulQueryBufSize, // Change this before checking in.
pszQueryText ); if (hr == E_OUTOFMEMORY ) { //
// Means there was insufficient length in the buffers.
//
if (ulLangBufSize > (100 * sizeof(WCHAR))) { FreeADsStr(pszLangBuf); pszLangBuf = (LPWSTR) AllocADsMem(ulLangBufSize + sizeof(WCHAR)); if (!pszLangBuf) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } }
if (ulQueryBufSize > (1024 * sizeof(WCHAR))) { FreeADsStr(pszQueryText); pszQueryText = (LPWSTR) AllocADsMem( ulQueryBufSize + sizeof(WCHAR) ); if (pszQueryText) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } }
hr = _pQuery->GetQuery( &ulLangBufSize, pszLangBuf, &ulQueryBufSize, // Change this before checking in.
pszQueryText ); } BAIL_ON_FAILURE(hr);
if (*pszLangBuf) { if (!_wcsicmp(L"SQL", pszLangBuf) || !_wcsicmp(L"WQL", pszLangBuf) ) { //
// This is a sql query and we need to process the query before
// pulling the options out of the query object.
//
hr = ProcessSQLQuery( pszQueryText, &pszFilter, &pSortKey ); BAIL_ON_FAILURE(hr);
} else if (!_wcsicmp(L"LDAP", pszLangBuf)) { //
// Neither SQL nor LDAP but the language is set which means
// we cannot handle this query.
//
pszFilter = AllocADsStr(pszQueryText); if (!pszFilter) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } } }
//
// At this point we need to go through and pick up all the properties.
// we know about and update our search preferences accordingly. Each of
// these properties has to be set and has to have some valid data.
//
//
// Start with the search scope.
//
hr = pPropList->Get(L"__SEARCH_SCOPE", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwSearchScope = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the synchronous/asynchronous pref.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_ASYNCHRONOUS", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
_searchPrefs._fAsynchronous = pPropVals->pPropArray[0].pUmiValue->bValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the deref aliases search pref.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_DEREF_ALIASES", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
_searchPrefs._dwDerefAliases = pPropVals->pPropArray[0].pUmiValue->bValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the size limit.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_SIZE_LIMIT", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwSizeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the time limit.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_TIME_LIMIT", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwTimeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the attributes only preference.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_ATTRIBTYPES_ONLY", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
_searchPrefs._fAttrsOnly = pPropVals->pPropArray[0].pUmiValue->bValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the search scope again ???
//
// __PADS_SEARCHPREF_SEARCH_SCOPE (duplicate for consistency cause it should be for all ideally).
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_TIMEOUT", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwTimeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// The page size is next.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_PAGESIZE", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwPageSize = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Get the paged time limit.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_PAGED_TIME_LIMIT", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwPagedTimeLimit = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Chase referrals comes next.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_CHASE_REFERRALS", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidLongProperty(pPropVals));
_searchPrefs._dwChaseReferrals = pPropVals->pPropArray[0].pUmiValue->uValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL; //
// Get the sort preferences ---> more complex do later.
//
// __PADS_SEARCHPREF_SORT_ON ---> potential candidate for all providers.
//
//
// Cache results.
//
pPropList->Get(L"__PADS_SEARCHPREF_CACHE_RESULTS", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
_searchPrefs._fCacheResults = pPropVals->pPropArray[0].pUmiValue->bValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// DirSync control --- do later.
// __PADS_SEARCHPREF_DIRSYNC
//
//
// Tombstone preferences.
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_TOMBSTONE", 0, &pPropVals); BAIL_ON_FAILURE(hr);
BAIL_ON_FAILURE(hr = VerifyValidBoolProperty(pPropVals));
_searchPrefs._fTombStone = pPropVals->pPropArray[0].pUmiValue->bValue[0];
pPropList->FreeMemory(0, (void *) pPropVals); pPropVals = NULL;
//
// Need to get the list of attributes.
//
//
hr = pPropList->Get(L"__PADS_SEARCHPREF_ATTRIBUTES", 0, &pPropVals); BAIL_ON_FAILURE(hr);
//
// Need to change to check for NULL then set count to -1.
//
pszAttrNames = pPropVals->pPropArray[0].pUmiValue->pszStrValue; dwAttrCount = pPropVals->pPropArray[0].uCount;
//
// Special case to ask for NULL with 0 to get all attributes.
//
if (!dwAttrCount && !pszAttrNames) { dwAttrCount = (DWORD) -1; } //
// Now that we have all the preferences, we can set the search prefs
// and also execute the search.
//
hr = ADsExecuteSearch( _searchPrefs, _pszADsPath, _pszLdapServer, _pszLdapDn, pszFilter, pszAttrNames, dwAttrCount, & _hSearchHandle ); BAIL_ON_FAILURE(hr);
_fSearchExecuted = TRUE;
error:
if (pPropVals) { //
// Guess we need to use the query to free this !
//
_pQuery->FreeMemory(0, (void *)pPropVals); } if (pPropList) { pPropList->Release(); }
if (pszLangBuf) { FreeADsStr(pszLangBuf); }
if (pszQueryText) { FreeADsStr(pszQueryText); }
if (pSortKey) { if (pSortKey->pszAttrType) { FreeADsStr(pSortKey->pszAttrType); } if (pSortKey->pszReserved) { FreeADsStr(pSortKey->pszReserved); }
FreeADsMem(pSortKey); }
if (FAILED(hr)) { //
// Should we really be doing this ?
//
LdapInitializeSearchPreferences(&_searchPrefs, FALSE); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::GetNextObject.
//
// Synopsis: This routine gets the next object in the result set. It calls
// get next row to get the next row and creates the equivalent
// cgenobj (need to add code to prepopulate the attributes).
//
// Arguments: None.
//
// Returns: S_OK, or any appropriate error code.
//
// Modifies: Internal search preferences and also state search handle.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::GetNextObject(IUnknown **pUnk) { HRESULT hr = S_OK; ADS_SEARCH_COLUMN adsColumn; BSTR ADsPath = NULL; LPWSTR pszParent = NULL; LPWSTR pszCN = NULL; PADSLDP ldapHandle = NULL; LDAPMessage *pldapMsg = NULL;
//
// Zero init the struct to make sure we can free in error path.
//
memset(&adsColumn, 0, sizeof(ADS_SEARCH_COLUMN));
ADsAssert(_fSearchExecuted);
if (!_hSearchHandle) { BAIL_ON_FAILURE(hr = E_FAIL); }
//
// Get the next row.
//
hr = ADsGetNextRow( _hSearchHandle, *_pCreds ); if (hr == S_ADS_NOMORE_ROWS) { //
// Hit end of enumeration.
//
*pUnk = NULL; RRETURN(S_FALSE); } else if (FAILED(hr)) { BAIL_ON_FAILURE(hr); }
//
// Fetch the path and use it to create the object.
//
hr = ADsGetColumn( _hSearchHandle, L"ADsPath", *_pCreds, _dwPort, &adsColumn ); BAIL_ON_FAILURE(hr);
if (adsColumn.dwADsType != ADSTYPE_CASE_IGNORE_STRING || adsColumn.dwNumValues != 1) { //
// Bad type or number of return values, this should never happen.
//
BAIL_ON_FAILURE(hr = E_FAIL); }
//
// Get the whole ldap message for the current row, that way we can
// prepopulate the object. Since we are picking up the actual message,
// we cannot rely on GetNextColumnName to work properly.
//
hr = ADsHelperGetCurrentRowMessage( _hSearchHandle, &ldapHandle, // need this when getting the actual attributes.
&pldapMsg ); BAIL_ON_FAILURE(hr);
//
//
// For creating the object, the parent path and the rdn is needed.
//
hr = BuildADsParentPath( adsColumn.pADsValues[0].CaseIgnoreString, &pszParent, &pszCN ); BAIL_ON_FAILURE(hr);
//
// Maybe we should just get all the values for this row and
// send into a constructor for the cgenobj ???
//
hr = CLDAPGenObject::CreateGenericObject( pszParent, pszCN, *_pCreds, ADS_OBJECT_BOUND, ldapHandle, pldapMsg, _pIID ? (*_pIID) : IID_IUmiObject, (void **) pUnk );
BAIL_ON_FAILURE(hr);
error:
if (pszParent) { FreeADsStr(pszParent); }
if (pszCN) { FreeADsStr(pszCN); }
//
// Calling this can not harm us.
//
ADsFreeColumn(&adsColumn);
if (FAILED(hr) && *pUnk) { (*pUnk)->Release(); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CUmiSearchHelper::ProcessSQLQuery (helper function).
//
// Synopsis: This routine takes the SQL Query text, parses it using the
// wmi query parser and converts the query to preferences on
// the underlying queryObjects interface proplist.
//
// Arguments: pszQueryText - SQL language query.
//
// Returns: S_OK, or any appropriate error code.
//
// Modifies: Search preferences on the underlying query object.
//
//----------------------------------------------------------------------------
HRESULT CUmiSearchHelper::ProcessSQLQuery( LPCWSTR pszQueryText, LPWSTR * ppszFilter, PADS_SORTKEY *ppADsSortKey ) { HRESULT hr = S_OK; IWbemQuery *pQuery = NULL; ULONG ulFeatures[] = { WMIQ_LF1_BASIC_SELECT, WMIQ_LF2_CLASS_NAME_IN_QUERY, WMIQ_LF6_ORDER_BY, WMIQ_LF24_UMI_EXTENSIONS }; SWbemRpnEncodedQuery *pRpn = NULL; LPWSTR *pszAttribArray = NULL; DWORD dwAttribCount = 0; LPWSTR pszFromListFilter = NULL; LPWSTR pszFilter = NULL; IUmiPropList *pIntfPropList = NULL; UMI_PROPERTY umiPropAttribs = { UMI_TYPE_LPWSTR, 1, UMI_OPERATION_UPDATE, L"__PADS_SEARCHPREF_ATTRIBUTES", NULL }; //
// Will likely need to set the attribute list.
//
UMI_PROPERTY pOneUmiProp[1]; pOneUmiProp[0] = umiPropAttribs;
UMI_PROPERTY_VALUES propUmiVals[1]; propUmiVals[0].uCount = 1; propUmiVals[0].pPropArray = pOneUmiProp;
ADsAssert(ppszFilter); *ppszFilter = NULL;
//
// Create the WBEM parser object.
//
hr = CoCreateInstance( CLSID_WbemQuery, NULL, CLSCTX_INPROC_SERVER, IID_IWbemQuery, (LPVOID *) &pQuery ); BAIL_ON_FAILURE(hr);
//
// Set the query into the parser and try and parse the query.
//
hr = pQuery->SetLanguageFeatures( 0, sizeof(ulFeatures)/sizeof(ULONG), ulFeatures ); BAIL_ON_FAILURE(hr);
hr = pQuery->Parse(L"SQL", pszQueryText, 0); BAIL_ON_FAILURE(hr);
hr = pQuery->GetAnalysis( WMIQ_ANALYSIS_RPN_SEQUENCE, 0, (LPVOID *) &pRpn ); BAIL_ON_FAILURE(hr);
if (!pRpn->m_uSelectListSize) { //
// Sanity check to make sure we are selecting something.
//
BAIL_ON_FAILURE(hr = E_FAIL); }
hr = HelperGetAttributeList( &dwAttribCount, &pszAttribArray, pRpn->m_uSelectListSize, pRpn->m_ppSelectList ); BAIL_ON_FAILURE(hr); //
// As of now the from list cannot have anything in other than *.
//
hr = HelperGetFromList( &pszFromListFilter, pRpn ); BAIL_ON_FAILURE(hr);
hr = HelperGetFilterFromWhereClause( &pszFilter, pRpn->m_uWhereClauseSize, pRpn->m_ppRpnWhereClause ); BAIL_ON_FAILURE(hr);
//
// See if we have an order by list, in SQL we support only one
// order by clause.
//
if (pRpn->m_uOrderByListSize) { hr = HelperGetSortKey(pRpn, ppADsSortKey); BAIL_ON_FAILURE(hr); } //
// Need to set the attribute list if applicable.
//
if ((dwAttribCount != (DWORD) -1) && dwAttribCount) { //
// Need to set the property on the interface proplist.
//
hr = _pQuery->GetInterfacePropList( 0, &pIntfPropList ); BAIL_ON_FAILURE(hr);
pOneUmiProp[0].uCount = dwAttribCount; pOneUmiProp[0].pUmiValue = (PUMI_VALUE) (LPVOID) pszAttribArray;
hr = pIntfPropList->Put( L"__PADS_SEARCHPREF_ATTRIBUTES", 0, propUmiVals ); BAIL_ON_FAILURE(hr);
} //
// Need to return the filter back.
//
*ppszFilter = pszFilter;
error:
if (pQuery) { pQuery->Release(); }
if (pszFromListFilter) { FreeADsStr(pszFromListFilter); } if (pIntfPropList) { pIntfPropList->Release(); }
//
// We might need to return this as a param.
//
if (FAILED(hr) && pszFilter) { FreeADsStr(pszFilter); }
RRETURN(hr); }
//****************************************************************************
// CQueryStack Implementation *
//****************************************************************************
//+---------------------------------------------------------------------------
// Function: CQueryStack::CQueryStack - Constructor.
//
// Synopsis: Initializes the underlying list to NULL and count to 0.
//
// Arguments: None.
//
// Returns: N/A.
//
// Modifies: All member variables.
//
//----------------------------------------------------------------------------
CQueryStack::CQueryStack(): _pStackList(NULL), _dwElementCount(0) { }
//+---------------------------------------------------------------------------
// Function: CQueryStack::~CQueryStack - Destructor.
//
// Synopsis: Frees the underlying list contents if applicable.
//
// Arguments: None.
//
// Returns: N/A.
//
// Modifies: N/A.
//
//----------------------------------------------------------------------------
CQueryStack::~CQueryStack() { if (_pStackList) { STACKLIST *pList = _pStackList; STACKLIST *pPrev = NULL; //
// Walk through and free the list.
//
while (pList) { pPrev = pList; pList = pList->pNext; //
// Need to free prev node and its contents.
//
CQueryStack::FreeStackEntry(pPrev); } _pStackList = NULL; } }
//+---------------------------------------------------------------------------
// Function: CQueryStack::Push.
//
// Synopsis: Pushes the node onto the stack and increases the count. The
// node is added to the head of the underlying list.
//
// Arguments: pszString - The string value of the node.
// dwType - The type of the node can either be
// a literal or an operator.
//
// Returns: S_OK or E_OUTOFMEMORY.
//
// Modifies: The underlying list.
//
//----------------------------------------------------------------------------
HRESULT CQueryStack::Push( LPWSTR pszString, DWORD dwType ) { HRESULT hr = S_OK; PSTACKLIST pStackEntry = NULL;
//
// Allocate the new node.
//
hr = CQueryStack::AllocateStackEntry( pszString, dwType, &pStackEntry ); if (FAILED(hr)) { BAIL_ON_FAILURE(hr); }
//
// If the list is not already then it is added to the head.
//
if (!this->_pStackList) { _pStackList = pStackEntry; } else { //
// Add new entry to the head of the list.
//
pStackEntry->pNext = _pStackList; _pStackList = pStackEntry; }
//
// Increment count as the add to list was successful.
//
_dwElementCount++;
error:
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CQueryStack::Pop.
//
// Synopsis: Removes node node from the stack and returns the contents.
// Node is removed from the head of the underlying list.
//
// Arguments: ppszString - Return ptr for string value of node.
// dwType - Return ptr for the type of the node.
//
// Returns: S_OK, E_OUTOFMEMORY or E_FAIL.
//
// Modifies: The underlying list.
//
//----------------------------------------------------------------------------
HRESULT CQueryStack::Pop( LPWSTR *ppszString, DWORD *pdwType ) { HRESULT hr = S_OK; PSTACKLIST pStackEntry = _pStackList;
if (!pStackEntry || !ppszString || !pdwType ) { BAIL_ON_FAILURE(hr = E_FAIL); }
//
// Initialize the return values.
//
*ppszString = NULL; *pdwType = (DWORD) -1;
if (pStackEntry->pszElement) { *ppszString = AllocADsStr(pStackEntry->pszElement); if (!*ppszString) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); } *pdwType = pStackEntry->dwElementType; } else { //
// Should never get here.
//
BAIL_ON_FAILURE(hr = E_FAIL); }
//
// Need to advance the list to the next node and free the
// contents of the current node.
//
_pStackList = _pStackList->pNext; CQueryStack::FreeStackEntry(pStackEntry);
//
// Decrement count as the remove from list was successful.
//
_dwElementCount--;
error:
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CQueryStack::IsEmpty.
//
// Synopsis: Returns TRUE or FALSE based on the contents of the stack.
//
// Arguments: N/A.
//
// Returns: TRUE or FALSE.
//
// Modifies: N/A
//
//----------------------------------------------------------------------------
BOOL CQueryStack::IsEmpty() { return (_dwElementCount == 0); }
//+---------------------------------------------------------------------------
// Function: CQueryStack::AllocateStackEntry - static helper routine.
//
// Synopsis: Allocates a stack node with the specified contents.
//
// Arguments: pszString - The string value of the node.
// dwType - The type of the node can either be
// a literal or an operator.
// ppStackEntry - Return value.
//
// Returns: S_OK, E_OUTOFMEMORY or E_FAIL.
//
// Modifies: ppStackEntry.
//
//----------------------------------------------------------------------------
HRESULT CQueryStack::AllocateStackEntry( LPWSTR pszString, DWORD dwType, STACKLIST **ppStackEntry ) { HRESULT hr = S_OK; LPWSTR pszTmpString = NULL;
if (!pszString || !dwType) { BAIL_ON_FAILURE(hr = E_FAIL); }
*ppStackEntry = NULL;
pszTmpString = AllocADsStr(pszString); if (!pszString) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
//
// Allocate the new stack node.
//
*ppStackEntry = (PSTACKLIST) AllocADsMem(sizeof(STACKLIST)); if (!*ppStackEntry) { BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); }
(*ppStackEntry)->pszElement = pszTmpString; (*ppStackEntry)->dwElementType = dwType; error:
if (FAILED(hr) && pszTmpString) { FreeADsStr(pszTmpString); }
RRETURN(hr); }
//+---------------------------------------------------------------------------
// Function: CQueryStack::FreeStackEntry - static helper routine.
//
// Synopsis: Frees contents of the stack node and the node itself.
//
// Arguments: pStackEntry - Pointer to stack node to free.
//
// Returns: N/A.
//
// Modifies: pStackEntry and contents.
//
//----------------------------------------------------------------------------
void CQueryStack::FreeStackEntry( PSTACKLIST pStackEntry ) { if (!pStackEntry) { return; }
//
// Free the string if there is one and then the node.
//
if (pStackEntry->pszElement) { FreeADsStr(pStackEntry->pszElement); } FreeADsMem(pStackEntry);
return; }
|