windows-nt/Source/XPSP1/NT/ds/adsi/nds/qryparse.cxx
2020-09-26 16:20:57 +08:00

1570 lines
46 KiB
C++

/*++
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<dwNumber-1;i++)
Stack.Pop();
}
}
hr = Stack.Current(&pSynNodeRed);
BAIL_ON_FAILURE(hr);
dwState = pSynNodeRed->_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;
}