/*++ Copyright (c) 1995 Microsoft Corporation Module Name: qryparse.cxx Abstract: Author: Felix Wong [t-FelixW] 05-Nov-1996 ++*/ #include "nds.hxx" #pragma hdrstop //#define DEBUG_DUMPSTACK //#define DEBUG_DUMPRULE #if (defined(DEBUG_DUMPSTACK) || defined (DEBUG_DUMPRULE)) #include "stdio.h" #endif #define MAPHEXTODIGIT(x) ( x >= '0' && x <= '9' ? (x-'0') : \ x >= 'A' && x <= 'F' ? (x-'A'+10) : \ x >= 'a' && x <= 'f' ? (x-'a'+10) : 0 ) // Action Table typedef struct _action{ DWORD type; DWORD dwState; }action; // Rule Table typedef struct _rule{ DWORD dwNumber; DWORD dwA; }rule; enum types { N, S, R, A }; #define X 99 action g_action[28][14] = { // ERROR ,LPARAN,RPARAN,OR, AND, NOT, APPROX,EQ, LE, GE, PRESNT,ATYPE, VAL, END, /*00*/ { {N,X },{S,2 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*01*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{A,X } }, /*02*/ { {N,X },{N,X },{N,X },{S,12},{S,11},{S,13},{N,X },{N,X },{N,X },{N,X },{N,X },{S,14},{N,X },{N,X } }, /*03*/ { {N,X },{N,X },{R,2 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*04*/ { {N,X },{N,X },{R,3 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*05*/ { {N,X },{N,X },{R,4 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*06*/ { {N,X },{N,X },{R,5 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*07*/ { {N,X },{N,X },{S,15},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*08*/ { {N,X },{N,X },{R,11},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*09*/ { {N,X },{N,X },{R,12},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*10*/ { {N,X },{N,X },{R,13},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*11*/ { {N,X },{S,2 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*12*/ { {N,X },{S,2 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*13*/ { {N,X },{S,2 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*14*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{S,20},{S,26},{S,22},{S,21},{S,23},{N,X },{N,X },{N,X } }, /*15*/ { {N,X },{R,1 },{R,1 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{R,1 } }, /*16*/ { {N,X },{N,X },{R,6 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*17*/ { {N,X },{S,2 },{R,9 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*18*/ { {N,X },{N,X },{R,7 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*19*/ { {N,X },{N,X },{R,8 },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*20*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{R,15},{N,X } }, /*21*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{R,16},{N,X } }, /*22*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{R,17},{N,X } }, /*23*/ { {N,X },{N,X },{R,18},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*24*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{S,25},{N,X } }, /*25*/ { {N,X },{N,X },{R,14},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } }, /*26*/ { {N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{R,19},{N,X } }, /*27*/ { {N,X },{N,X },{R,10},{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X },{N,X } } }; enum non_terminals { NONTERM_F, NONTERM_FC, NONTERM_AND, NONTERM_OR, NONTERM_NOT, NONTERM_FL, NONTERM_ITM, NONTERM_SMP, NONTERM_FT, NONTERM_PRS }; rule g_rule[] = { // 1)No. of non-terminals and terminals on the right hand side // 2)The Parent /*00*/ {0, 0, }, /*01*/ {3, NONTERM_F, }, /*02*/ {1, NONTERM_FC, }, /*03*/ {1, NONTERM_FC, }, /*04*/ {1, NONTERM_FC, }, /*05*/ {1, NONTERM_FC, }, /*06*/ {2, NONTERM_AND, }, /*07*/ {2, NONTERM_OR, }, /*08*/ {2, NONTERM_NOT, }, /*09*/ {1, NONTERM_FL, }, /*10*/ {2, NONTERM_FL, }, /*11*/ {1, NONTERM_ITM, }, /*12*/ {1, NONTERM_ITM, }, /*13*/ {1, NONTERM_ITM, }, /*14*/ {3, NONTERM_SMP, }, /*15*/ {1, NONTERM_FT, }, /*16*/ {1, NONTERM_FT, }, /*17*/ {1, NONTERM_FT, }, /*18*/ {2, NONTERM_PRS, }, /*19*/ {1, NONTERM_FT, } }; #ifdef DEBUG_DUMPRULE LPWSTR g_rgszRule[] = { /*00*/ L"", /*01*/ L"F->(FC)", /*02*/ L"FC->AND", /*03*/ L"FC->OR", /*04*/ L"FC->NOT", /*05*/ L"FC->ITM", /*06*/ L"AND->&FL", /*07*/ L"OR->|FL", /*08*/ L"NOT->!F", /*09*/ L"FL->F", /*10*/ L"FL->F FL", /*11*/ L"ITM->SMP", /*12*/ L"ITM->PRS", /*13*/ L"ITM->STR", /*14*/ L"SMP->ATR FT VAL", /*15*/ L"FT->~=", /*16*/ L"FT->>=", /*17*/ L"FT-><=", /*18*/ L"PRS->ATR=*", /*19*/ L"FT->=" }; #endif DWORD g_goto[28][10] = { // F, FC, AND, OR, NOT, FL, ITM, SMP, FT, PRS, /*00*/ {1, X, X, X, X, X, X, X, X, X }, /*01*/ {X, X, X, X, X, X, X, X, X, X }, /*02*/ {X, 7, 3, 4, 5, X, 6, 8, X, 9 }, /*03*/ {X, X, X, X, X, X, X, X, X, X }, /*04*/ {X, X, X, X, X, X, X, X, X, X }, /*05*/ {X, X, X, X, X, X, X, X, X, X }, /*06*/ {X, X, X, X, X, X, X, X, X, X }, /*07*/ {X, X, X, X, X, X, X, X, X, X }, /*08*/ {X, X, X, X, X, X, X, X, X, X }, /*09*/ {X, X, X, X, X, X, X, X, X, X }, /*10*/ {X, X, X, X, X, X, X, X, X, X }, /*11*/ {17, X, X, X, X, 16, X, X, X, X }, /*12*/ {17, X, X, X, X, 18, X, X, X, X }, /*13*/ {19, X, X, X, X, X, X, X, X, X }, /*14*/ {X, X, X, X, X, X, X, X, 24, X }, /*15*/ {X, X, X, X, X, X, X, X, X, X }, /*16*/ {X, X, X, X, X, X, X, X, X, X }, /*17*/ {17, X, X, X, X, 27, X, X, X, X }, /*18*/ {X, X, X, X, X, X, X, X, X, X }, /*19*/ {X, X, X, X, X, X, X, X, X, X }, /*20*/ {X, X, X, X, X, X, X, X, X, X }, /*21*/ {X, X, X, X, X, X, X, X, X, X }, /*22*/ {X, X, X, X, X, X, X, X, X, X }, /*23*/ {X, X, X, X, X, X, X, X, X, X }, /*24*/ {X, X, X, X, X, X, X, X, X, X }, /*25*/ {X, X, X, X, X, X, X, X, X, X }, /*26*/ {X, X, X, X, X, X, X, X, X, X }, /*27*/ {X, X, X, X, X, X, X, X, X, X } }; HRESULT MapTokenToType( DWORD dwToken, DWORD *pdwType ) { DWORD dwType; switch(dwToken) { case TOKEN_EQ: dwType = QUERY_EQUAL; break; case TOKEN_LE: dwType = QUERY_LE; break; case TOKEN_GE: dwType = QUERY_GE; break; case TOKEN_APPROX_EQ: dwType = QUERY_APPROX; break; default: return (E_ADS_INVALID_FILTER); } *pdwType = dwType; return (S_OK); } HRESULT Parse( LPWSTR szQuery, CQueryNode **ppNode, CAttrList **ppAttrList ) { CStack Stack; CQryLexer Query(szQuery); LPWSTR lexeme; DWORD dwToken; DWORD dwState; HRESULT hr = E_ADS_INVALID_FILTER; CAttrList* pAttrList = new CAttrList; if (!pAttrList) return E_OUTOFMEMORY; CSyntaxNode *pSynNode = NULL; CQueryNode *pNode1 = NULL; CQueryNode *pNode2 = NULL; CQueryNode *pNode3 = NULL; // Push in State 0 pSynNode = new CSyntaxNode; Stack.Push(pSynNode); pSynNode = NULL; #ifdef DEBUG_DUMPSTACK Stack.Dump(); #endif while (1) { // Getting information for this iteration, dwToken and dwState hr = Query.GetCurrentToken( &lexeme, &dwToken ); BAIL_ON_FAILURE(hr); hr = Stack.Current(&pSynNode); BAIL_ON_FAILURE(hr); dwState = pSynNode->_dwState; pSynNode = NULL; // Analysing and processing the data if (g_action[dwState][dwToken].type == S) { pSynNode = new CSyntaxNode; pSynNode->_dwState = g_action[dwState][dwToken].dwState; pSynNode->_dwToken = dwToken; switch (dwToken) { case TOKEN_ATTRTYPE: { hr = pAttrList->Add(lexeme); BAIL_ON_FAILURE(hr); } case TOKEN_ATTRVAL: // both TOKEN_ATTRTYPE and TOKEN_ATTRVAL will get here { LPWSTR szValue = AllocADsStr(lexeme); if (!szValue) { hr = E_OUTOFMEMORY; goto error; } pSynNode->SetNode(szValue); break; } } hr = Stack.Push(pSynNode); BAIL_ON_FAILURE(hr); pSynNode = NULL; hr = Query.GetNextToken( &lexeme, &dwToken ); BAIL_ON_FAILURE(hr); #ifdef DEBUG_DUMPSTACK Stack.Dump(); #endif } else if (g_action[dwState][dwToken].type == R) { DWORD dwRule = g_action[dwState][dwToken].dwState; DWORD dwNumber = g_rule[dwRule].dwNumber; #ifdef DEBUG_DUMPRULE wprintf(L"%s\n",g_rgszRule[dwRule]); #endif pSynNode = new CSyntaxNode; CSyntaxNode *pSynNodeRed; switch (dwRule) { case 1: // Reduction of Basic Filter rule { // Getting the middle node hr = Stack.Pop(); BAIL_ON_FAILURE(hr); hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pSynNodeRed->_pNode ); pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = Stack.Pop(); BAIL_ON_FAILURE(hr); break; } case 18: // Reduction of PRESENT rule { // Getting second node LPWSTR szType; hr = Stack.Pop(); BAIL_ON_FAILURE(hr); hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); szType = pSynNodeRed->_szValue; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = MakeLeaf( szType, &pNode1 ); BAIL_ON_FAILURE(hr); hr = MakeNode( QUERY_PRESENT, pNode1, NULL, &pNode2 ); BAIL_ON_FAILURE(hr); pNode1 = NULL; pSynNode->SetNode( pNode2 ); pNode2 = NULL; break; } case 14: // Reduction of SMP rule { LPWSTR szType; LPWSTR szValue; DWORD dwType; DWORD dwToken; hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); szValue = pSynNodeRed->_szValue; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); dwToken = (DWORD)pSynNodeRed->_dwFilterType; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); szType = pSynNodeRed->_szValue; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = MakeLeaf( szType, &pNode1 ); BAIL_ON_FAILURE(hr); hr = MakeLeaf( szValue, &pNode2 ); BAIL_ON_FAILURE(hr); hr = MapTokenToType( dwToken, &dwType ); BAIL_ON_FAILURE(hr); hr = MakeNode( dwType, pNode1, pNode2, &pNode3 ); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pNode3 ); pNode1 = NULL; pNode2 = NULL; pNode3 = NULL; break; } case 6: // Reduction of AND, OR rules case 7: { DWORD dwType; Stack.Pop(&pSynNodeRed); pSynNode->SetNode( pSynNodeRed->_pNode ); pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; Stack.Pop(); // Adding in the type information if (dwRule == 6) dwType = QUERY_AND; else dwType = QUERY_OR; pSynNode->_pNode->_dwType = dwType; break; } case 10: // Reduction of FL rule { DWORD dwType; hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pNode2 = pSynNodeRed->_pNode; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pNode1 = pSynNodeRed->_pNode; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; if (pNode2->_dwType == QUERY_UNKNOWN) { // It's not new node, append to node1 hr = pNode2->AddChild(pNode1); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pNode2 ); pNode1 = NULL; pNode2 = NULL; } else { // New node hr = MakeNode( QUERY_UNKNOWN, pNode1, pNode2, &pNode3 ); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pNode3 ); pNode1 = NULL; pNode2 = NULL; pNode3 = NULL; } break; } case 9: // Reduction of FL rule { DWORD dwType; hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pNode1 = pSynNodeRed->_pNode; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = MakeNode( QUERY_UNKNOWN, pNode1, NULL, &pNode3 ); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pNode3 ); pNode1 = NULL; pNode3 = NULL; break; } case 8: // Reduction of NOT rule { Stack.Pop(&pSynNodeRed); pNode1 = pSynNodeRed->_pNode; pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; hr = MakeNode( QUERY_NOT, pNode1, NULL, &pNode2 ); BAIL_ON_FAILURE(hr); pNode1 = NULL; hr = Stack.Pop(); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pNode2 ); pNode2 = NULL; break; } case 15: // Reduction of FT rule case 16: case 17: case 19: { // Propagating the last entry hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pSynNodeRed->_dwToken ); pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; break; } default: { // For all the other rules, we propogate the last entry hr = Stack.Pop(&pSynNodeRed); BAIL_ON_FAILURE(hr); pSynNode->SetNode( pSynNodeRed->_pNode ); pSynNodeRed->_dwType = SNODE_NULL; delete pSynNodeRed; for (DWORD i = 0;i_dwState; DWORD A = g_rule[dwRule].dwA; pSynNode->_dwState = g_goto[dwState][A]; pSynNode->_dwToken = A; hr = Stack.Push(pSynNode); BAIL_ON_FAILURE(hr); pSynNode = NULL; #ifdef DEBUG_DUMPSTACK Stack.Dump(); #endif } else if (g_action[dwState][dwToken].type == A){ hr = Stack.Pop(&pSynNode); BAIL_ON_FAILURE(hr); *ppNode = pSynNode->_pNode; *ppAttrList = pAttrList; pSynNode->_dwType = SNODE_NULL; delete pSynNode; return S_OK; } else { hr = E_ADS_INVALID_FILTER; goto error; } } error: if (pAttrList) { delete pAttrList; } if (pSynNode) { delete pSynNode; } if (pNode1) { delete pNode1; } if (pNode2) { delete pNode2; } if (pNode3) { delete pNode3; } return hr; } CStack::CStack() { _dwStackIndex = 0; } CStack::~CStack() { DWORD dwIndex = _dwStackIndex; while (dwIndex > 0) { CSyntaxNode *pNode; pNode = _Stack[--dwIndex]; delete pNode; } } #ifdef DEBUG_DUMPSTACK void CStack::Dump() { DWORD dwIndex = _dwStackIndex; printf("Stack:\n"); while (dwIndex > 0) { CSyntaxNode *pNode; pNode = _Stack[--dwIndex]; printf( "State=%5.0d, Token=%5.0d\n", pNode->_dwState, pNode->_dwToken ); } } #endif HRESULT CStack::Push(CSyntaxNode* pNode) { if (_dwStackIndex < MAXVAL) { _Stack[_dwStackIndex++] = pNode; return S_OK; } else return E_FAIL; } HRESULT CStack::Pop(CSyntaxNode** ppNode) { if (_dwStackIndex > 0) { *ppNode = _Stack[--_dwStackIndex]; return S_OK; } else { return E_FAIL; } } HRESULT CStack::Pop() { if (_dwStackIndex > 0) { CSyntaxNode *pNode; pNode = _Stack[--_dwStackIndex]; delete pNode; return S_OK; } else { return E_FAIL; } } HRESULT CStack::Current(CSyntaxNode **ppNode) { if (_dwStackIndex > 0) { *ppNode = _Stack[_dwStackIndex-1]; return S_OK; } else { return E_FAIL; } } CAttrList::CAttrList() { _rgAttr = NULL; _dwAttrCur = 0; } CAttrList::~CAttrList() { if (_rgAttr) { for (DWORD i=0;i<_dwAttrCur;i++) FreeADsStr(_rgAttr[i].szName); FreeADsMem(_rgAttr); } } HRESULT CAttrList::Add(LPWSTR szName) { HRESULT hr = S_OK; LPWSTR pszTemp = NULL; for (DWORD i=0;i<_dwAttrCur;i++) { if (_wcsicmp( szName, _rgAttr[i].szName ) == 0) break; } if (i != _dwAttrCur) // does not loop till the end, entry exist already return S_OK; LPWSTR szAttr = AllocADsStr(szName); if (!szAttr) return E_OUTOFMEMORY; if (_dwAttrCur == _dwAttrMax) { if (!_rgAttr) { _rgAttr = (AttrNode*)AllocADsMem(ATTRNODE_INITIAL*sizeof(AttrNode)); if (!_rgAttr) { hr = E_OUTOFMEMORY; goto error; } _dwAttrMax = ATTRNODE_INITIAL; } else { _rgAttr = (AttrNode*)ReallocADsMem( (void*)_rgAttr, _dwAttrMax*sizeof(AttrNode), (_dwAttrMax+ATTRNODE_INC)*sizeof(AttrNode) ); if (!_rgAttr) { hr = E_OUTOFMEMORY; goto error; } _dwAttrMax+= ATTRNODE_INC; } } _rgAttr[_dwAttrCur].szName = szAttr; _rgAttr[_dwAttrCur].dwType = 0; //UNKNOWN at this point _dwAttrCur++; return S_OK; error: if (szAttr) FreeADsStr(szAttr); return (hr); } HRESULT CAttrList::SetupType(LPWSTR szConnection) { DWORD dwStatus; HRESULT hr=S_OK; HANDLE hOperationData = NULL; DWORD dwNumberOfEntries; DWORD dwInfoType; LPNDS_ATTR_DEF lpAttrDefs = NULL; HANDLE hConnection = NULL; DWORD i,j,k; dwStatus = NwNdsOpenObject( szConnection, NULL, NULL, &hConnection, NULL, NULL, NULL, 0, 0 ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto error; } dwStatus = NwNdsCreateBuffer( NDS_SCHEMA_READ_ATTR_DEF, &hOperationData ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto error; } for (i=0;i<_dwAttrCur;i++) { dwStatus = NwNdsPutInBuffer( _rgAttr[i].szName, 0, NULL, 0, 0, hOperationData ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto error; } } dwStatus = NwNdsReadAttrDef( hConnection, NDS_INFO_NAMES_DEFS, &hOperationData ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); BAIL_ON_FAILURE(hr); } dwStatus = NwNdsGetAttrDefListFromBuffer( hOperationData, &dwNumberOfEntries, &dwInfoType, (LPVOID *) &lpAttrDefs ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); goto error; } if (dwNumberOfEntries != _dwAttrCur) { hr = E_ADS_INVALID_FILTER; goto error; } for (j = 0; j < dwNumberOfEntries ; j++ ) { for (k = 0; k < dwNumberOfEntries; k++) { if (_wcsicmp( _rgAttr[k].szName, lpAttrDefs[j].szAttributeName ) == 0) { _rgAttr[k].dwType = lpAttrDefs[j].dwSyntaxID; break; } } if (k == dwNumberOfEntries) // cannot find entry goto error; } error: if (hOperationData) NwNdsFreeBuffer( hOperationData ); if (hConnection) NwNdsCloseObject( hConnection); RRETURN(hr); } HRESULT CAttrList::GetType(LPWSTR szName, DWORD *pdwType) { for (DWORD i=0;i<_dwAttrCur;i++) { if (_wcsicmp( szName, _rgAttr[i].szName ) == 0) break; } if (i == _dwAttrCur) // Cannot find attribute return E_FAIL; *pdwType = _rgAttr[i].dwType; return S_OK; } CSyntaxNode::CSyntaxNode() { _dwType = SNODE_NULL; _dwToken = 0; _dwState = 0; _pNode = 0; } CSyntaxNode::~CSyntaxNode() { switch (_dwType) { case SNODE_SZ: FreeADsStr(_szValue); break; case SNODE_NODE: delete _pNode; break; default: break; } } void CSyntaxNode::SetNode( CQueryNode *pNode ) { _pNode = pNode; _dwType = SNODE_NODE; } void CSyntaxNode::SetNode( LPWSTR szValue ) { _szValue = szValue; _dwType = SNODE_SZ; } void CSyntaxNode::SetNode( DWORD dwFilterType ) { _dwFilterType = dwFilterType; _dwType = SNODE_FILTER; } //+--------------------------------------------------------------------------- // // Function: CQueryNode::CQueryNode // // Synopsis: Constructor of the CQueryNode // // Arguments: // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- CQueryNode::CQueryNode() { _dwType = 0; _szValue = NULL; _dwQueryNode = 0; _rgQueryNode = NULL; _dwQueryNodeMax = 0; } //+--------------------------------------------------------------------------- // // Function: CQueryNode::SetToString // // Synopsis: Set the Node to be a String Node // // Arguments: szValue value of the string // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT CQueryNode::SetToString( LPWSTR szValue ) { _szValue = szValue; /* _szValue = AllocADsStr(szValue); if (!_szValue) { return E_OUTOFMEMORY; } */ _dwType = QUERY_STRING; return S_OK; } //+--------------------------------------------------------------------------- // // Function: CQueryNode::~CQueryNode // // Synopsis: Destructor of the CQueryNode // // Arguments: // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- CQueryNode::~CQueryNode() { if (_szValue) FreeADsStr(_szValue); if (_rgQueryNode) { for (DWORD i=0;i<_dwQueryNode;i++) { delete _rgQueryNode[i]; } FreeADsMem(_rgQueryNode); } } //+--------------------------------------------------------------------------- // // Function: CQueryNode::AddChild // // Synopsis: Add a child to the node // // Arguments: CQueryNode *pChild pointer to the child to be added // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT CQueryNode::AddChild(CQueryNode *pChild) { if (_dwQueryNode == _dwQueryNodeMax) { if (!_rgQueryNode) { _rgQueryNode = (CQueryNode**)AllocADsMem(QUERYNODE_INITIAL*sizeof(CQueryNode*)); if (!_rgQueryNode) { return E_OUTOFMEMORY; } _dwQueryNodeMax = QUERYNODE_INITIAL; } else { _rgQueryNode = (CQueryNode**)ReallocADsMem( (void*)_rgQueryNode, _dwQueryNodeMax*sizeof(CQueryNode*), (_dwQueryNodeMax+QUERYNODE_INC)*sizeof(CQueryNode*) ); if (!_rgQueryNode) { return E_OUTOFMEMORY; } _dwQueryNodeMax+= QUERYNODE_INC; } } _rgQueryNode[_dwQueryNode] = pChild; _dwQueryNode++; return S_OK; } //+--------------------------------------------------------------------------- // // Function: CQueryNode::GenerateNDSTree // // Synopsis: Generate an NDS tree with the current CQueryNode // // Arguments: pAttrList list of attributes to get syntax info // ppNDSSearchTree output of NDS Search Tree generated // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT CQueryNode::GenerateNDSTree( CAttrList *pAttrList, LPQUERY_NODE *ppNDSSearchTree ) { HRESULT hr = E_FAIL; DWORD dwOperation; DWORD dwStatus = 0; LPWSTR szAttr = NULL; LPWSTR szValue = NULL; LPQUERY_NODE pQueryNode1 = NULL; LPQUERY_NODE pQueryNode2 = NULL; LPQUERY_NODE pQueryNode3 = NULL; // Looking at type of operation switch (_dwType) { case QUERY_EQUAL: case QUERY_LE: case QUERY_GE: case QUERY_APPROX: case QUERY_PRESENT: { ASN1_TYPE_1 Asn1_WSTR; ASN1_TYPE_7 Asn1_BOOL; ASN1_TYPE_8 Asn1_DWORD; ASN1_TYPE_9 Asn1_Binary; void* pValue = NULL; DWORD dwSyntax; DWORD dwAttrType = 0; LPWSTR pszTemp = NULL; // Getting left node if (_rgQueryNode[0] && _rgQueryNode[0]->_dwType == QUERY_STRING) { szAttr = AllocADsStr(_rgQueryNode[0]->_szValue); if (!szAttr) { hr = E_OUTOFMEMORY; goto error; } } else { // No nodes available goto error; } // Getting right node if (_rgQueryNode[1] && _rgQueryNode[1]->_dwType == QUERY_STRING) { // Get syntax info of right node from attribute list hr = pAttrList->GetType( szAttr, &dwAttrType ); BAIL_ON_FAILURE(hr); // Format the node depending on the syntax switch (dwAttrType) { // WIDE STRING case NDS_SYNTAX_ID_1: case NDS_SYNTAX_ID_2: case NDS_SYNTAX_ID_3: case NDS_SYNTAX_ID_4: case NDS_SYNTAX_ID_5: case NDS_SYNTAX_ID_10: case NDS_SYNTAX_ID_11: case NDS_SYNTAX_ID_20: szValue = AllocADsStr(_rgQueryNode[1]->_szValue); if (!szValue) { hr = E_OUTOFMEMORY; goto error; } Asn1_WSTR.DNString = szValue; pValue = (void*)&Asn1_WSTR; break; // BOOLEAN case NDS_SYNTAX_ID_7: Asn1_BOOL.Boolean = _wtoi(_rgQueryNode[1]->_szValue); pValue = (void*)&Asn1_BOOL; break; // Binary Strings case NDS_SYNTAX_ID_9: { // // change the unicode form of binary encoded data // to binary // L"0135ABCDEF0" gets changed to 0x0135ABCDEF0 // same as the Ldap client code. // hr = ADsDecodeBinaryData ( _rgQueryNode[1]->_szValue, &Asn1_Binary.OctetString, &Asn1_Binary.Length); BAIL_ON_FAILURE(hr); pValue = (void*)&Asn1_Binary; } break; // TimeStamp case NDS_SYNTAX_ID_24 : { SYSTEMTIME st; TCHAR sz[3]; LPWSTR pszSrc = _rgQueryNode[1]->_szValue; // // Year // sz[0] = pszSrc[0]; sz[1] = pszSrc[1]; sz[2] = TEXT('\0'); st.wYear = (WORD) _ttoi(sz); if (st.wYear < 50) { st.wYear += 2000; } else { st.wYear += 1900; } // // Month // sz[0] = pszSrc[2]; sz[1] = pszSrc[3]; st.wMonth = (WORD) _ttoi(sz); // // Day // sz[0] = pszSrc[4]; sz[1] = pszSrc[5]; st.wDay = (WORD) _ttoi(sz); // // Hour // sz[0] = pszSrc[6]; sz[1] = pszSrc[7]; st.wHour = (WORD) _ttoi(sz); // // Minute // sz[0] = pszSrc[8]; sz[1] = pszSrc[9]; st.wMinute = (WORD) _ttoi(sz); // // Second // sz[0] = pszSrc[10]; sz[1] = pszSrc[11]; st.wSecond = (WORD) _ttoi(sz); st.wMilliseconds = 0; hr = ConvertSYSTEMTIMEtoDWORD( &st, &Asn1_DWORD.Integer ); BAIL_ON_FAILURE (hr); pValue = (void*)&Asn1_DWORD; break; } // DWORD case NDS_SYNTAX_ID_8 : case NDS_SYNTAX_ID_22 : case NDS_SYNTAX_ID_27 : Asn1_DWORD.Integer = _wtol(_rgQueryNode[1]->_szValue); pValue = (void*)&Asn1_DWORD; break; case NDS_SYNTAX_ID_6 : case NDS_SYNTAX_ID_13 : case NDS_SYNTAX_ID_14 : case NDS_SYNTAX_ID_15 : case NDS_SYNTAX_ID_16 : case NDS_SYNTAX_ID_17 : case NDS_SYNTAX_ID_18 : case NDS_SYNTAX_ID_19 : case NDS_SYNTAX_ID_23 : case NDS_SYNTAX_ID_25 : case NDS_SYNTAX_ID_26 : default: hr = E_ADS_CANT_CONVERT_DATATYPE; goto error; break; } } hr = MapQueryToNDSType( _dwType, &dwOperation ); BAIL_ON_FAILURE (hr); dwStatus = NwNdsCreateQueryNode( dwOperation, szAttr, dwAttrType, pValue, ppNDSSearchTree ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); RRETURN (hr); } if (szAttr) FreeADsStr(szAttr); if (szValue) FreeADsStr(szValue); break; } case QUERY_AND: case QUERY_OR: { hr = MapQueryToNDSType( _dwType, &dwOperation ); BAIL_ON_FAILURE (hr); // Create first node if (!_rgQueryNode[0]) goto error; hr = _rgQueryNode[0]->GenerateNDSTree( pAttrList, &pQueryNode1 ); BAIL_ON_FAILURE (hr); // Go through a loop creating the rest for (DWORD i=1;i<_dwQueryNode;i++) { if (!_rgQueryNode[i]) goto error; hr = _rgQueryNode[i]->GenerateNDSTree( pAttrList, &pQueryNode2 ); BAIL_ON_FAILURE (hr); dwStatus = NwNdsCreateQueryNode( dwOperation, pQueryNode1, NULL, //not used since this is AND/OR/NOT pQueryNode2, &pQueryNode3 ); if (dwStatus) { hr = HRESULT_FROM_WIN32(GetLastError()); RRETURN (hr); } pQueryNode1 = pQueryNode3; } *ppNDSSearchTree = pQueryNode1; break; } case QUERY_NOT: { hr = MapQueryToNDSType( _dwType, &dwOperation ); BAIL_ON_FAILURE (hr); // Create first node if (!_rgQueryNode[0]) goto error; hr = _rgQueryNode[0]->GenerateNDSTree( pAttrList, &pQueryNode1 ); BAIL_ON_FAILURE (hr); hr = NwNdsCreateQueryNode( dwOperation, pQueryNode1, NULL, NULL, &pQueryNode3 ); BAIL_ON_FAILURE (hr); *ppNDSSearchTree = pQueryNode3; break; } default: goto error; } RRETURN(hr); error: if (pQueryNode1) NwNdsDeleteQueryTree(pQueryNode1); if (pQueryNode2) NwNdsDeleteQueryTree(pQueryNode2); if (szAttr) FreeADsStr(szAttr); if (szValue) FreeADsStr(szValue); return hr; } //+--------------------------------------------------------------------------- // // Function: CQueryNode::MapQueryToNDSType // // Synopsis: Maps the node type to the equivalent NDS types // // Arguments: dwType input type // pdwNDSType output type // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT CQueryNode::MapQueryToNDSType( DWORD dwType, DWORD *pdwNDSType ) { DWORD dwNDSType; switch(dwType) { case QUERY_EQUAL: dwNDSType = NDS_QUERY_EQUAL; break; case QUERY_LE: dwNDSType = NDS_QUERY_LE; break; case QUERY_GE: dwNDSType = NDS_QUERY_GE; break; case QUERY_APPROX: dwNDSType = NDS_QUERY_APPROX; break; case QUERY_PRESENT: dwNDSType = NDS_QUERY_PRESENT; break; case QUERY_NOT: dwNDSType = NDS_QUERY_NOT; break; case QUERY_AND: dwNDSType = NDS_QUERY_AND; break; case QUERY_OR: dwNDSType = NDS_QUERY_OR; break; default: return (E_ADS_INVALID_FILTER); } *pdwNDSType = dwNDSType; return (S_OK); } // Helper Functions for creating nodes using the CQueryNode Class //+--------------------------------------------------------------------------- // // Function: MakeNode // // Synopsis: Make a node with the input values // // Arguments: dwType type of node // pLQueryNode pointer to left node // pRQueryNode pointer to right node // ppQueryNodeReturn pointer to Return Node // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT MakeNode( DWORD dwType, CQueryNode *pLQueryNode, CQueryNode *pRQueryNode, CQueryNode **ppQueryNodeReturn ) { HRESULT hr = S_OK; CQueryNode *pQueryNode = new CQueryNode(); if (!pQueryNode) return E_OUTOFMEMORY; pQueryNode->_dwType = dwType; hr = pQueryNode->AddChild(pLQueryNode); BAIL_ON_FAILURE(hr); if (pRQueryNode) { pQueryNode->AddChild(pRQueryNode); BAIL_ON_FAILURE(hr); } *ppQueryNodeReturn = pQueryNode; RRETURN(hr); error: delete pQueryNode; RRETURN(hr); } //+--------------------------------------------------------------------------- // // Function: MakeLeaf // // Synopsis: Constructor of the CQueryNode // // Arguments: szValue value of the string // ppQueryNodeReturn the return node // // Returns: // // Modifies: // // History: 11-12-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT MakeLeaf( LPWSTR szValue, CQueryNode **ppQueryNodeReturn ) { HRESULT hr = S_OK; CQueryNode *pQueryNode = new CQueryNode(); if (!pQueryNode) return E_OUTOFMEMORY; hr = pQueryNode->SetToString(szValue); BAIL_ON_FAILURE(hr); *ppQueryNodeReturn = pQueryNode; RRETURN(hr); error: delete pQueryNode; RRETURN(hr); } //+--------------------------------------------------------------------------- // // Function: ADsNdsGenerateParseTree // // Synopsis: Generate an NDS search tree to be used as inputs to NDS search // functions // // Arguments: pszCommandText - Command text for the search // szConnection - server to get the schema from // ppQueryNode - the generated NDS search tree // // Returns: HRESULT // S_OK NO ERROR // E_OUTOFMEMORY no memory // // Modifies: // // History: 10-29-96 Felix Wong Created. // //---------------------------------------------------------------------------- HRESULT AdsNdsGenerateParseTree( LPWSTR szCommandText, LPWSTR szConnection, LPQUERY_NODE *ppQueryNode ) { HRESULT hr; LPQUERY_NODE pNDSSearchTree; CQueryNode *pNode = NULL; CAttrList *pAttrList = NULL; // Generate the parse tree and the attribute list hr = Parse( szCommandText, &pNode, &pAttrList ); BAIL_ON_FAILURE(hr); // Setup syntax information in the attribute list hr = pAttrList->SetupType(szConnection); BAIL_ON_FAILURE(hr); // Generate the NDS tree hr = pNode->GenerateNDSTree( pAttrList, &pNDSSearchTree ); BAIL_ON_FAILURE(hr); *ppQueryNode = pNDSSearchTree; error: if (pNode) delete pNode; if (pAttrList) delete pAttrList; return hr; }