mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1491 lines
28 KiB
1491 lines
28 KiB
//****************************************************************************
|
|
//
|
|
// Module: ULS.DLL
|
|
// File: filter.cpp
|
|
// Content: This file contains the filter object.
|
|
// History:
|
|
// Tue 12-Nov-1996 15:50:00 -by- Chu, Lon-Chan [lonchanc]
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1995-1996
|
|
//
|
|
//****************************************************************************
|
|
|
|
#include "ulsp.h"
|
|
#include "filter.h"
|
|
#include "sputils.h"
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::CFilter
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
CFilter::CFilter ( ILS_FILTER_TYPE Type )
|
|
:
|
|
m_nSignature (ILS_FILTER_SIGNATURE),
|
|
m_cRefs (0),
|
|
m_Op (ILS_FILTEROP_NONE),
|
|
m_cSubFilters (0),
|
|
m_pszValue (NULL),
|
|
m_NameType (ILS_ATTRNAME_UNKNOWN),
|
|
m_Type (Type)
|
|
{
|
|
// Initialize individual members based on filter type
|
|
//
|
|
ZeroMemory (&m_Name, sizeof (m_Name));
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::~CFilter
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
CFilter::~CFilter ( VOID )
|
|
{
|
|
ASSERT (m_Type == ILS_FILTERTYPE_COMPOSITE || m_Type == ILS_FILTERTYPE_SIMPLE);
|
|
|
|
// Common members
|
|
//
|
|
m_nSignature = -1;
|
|
|
|
// Clean up individual members based on filter type
|
|
//
|
|
if (m_Type == ILS_FILTERTYPE_COMPOSITE)
|
|
{
|
|
m_SubFilters.Flush();
|
|
}
|
|
else
|
|
{
|
|
FreeName ();
|
|
FreeValue ();
|
|
}
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::QueryInterface
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
QueryInterface ( REFIID riid, VOID **ppv )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*ppv = NULL;
|
|
|
|
if (riid == IID_IIlsFilter || riid == IID_IUnknown)
|
|
{
|
|
*ppv = (IIlsFilter *) this;
|
|
}
|
|
|
|
if (*ppv != NULL)
|
|
((IUnknown *) *ppv)->AddRef();
|
|
else
|
|
hr = ILS_E_NO_INTERFACE;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::AddRef
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP_(ULONG) CFilter::
|
|
AddRef ( VOID )
|
|
{
|
|
DllLock();
|
|
|
|
MyDebugMsg ((DM_REFCOUNT, "CFilter::AddRef: ref=%ld\r\n", m_cRefs));
|
|
::InterlockedIncrement (&m_cRefs);
|
|
return m_cRefs;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::Release
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP_(ULONG) CFilter::
|
|
Release ( VOID )
|
|
{
|
|
ASSERT (m_cRefs > 0);
|
|
|
|
DllRelease();
|
|
|
|
MyDebugMsg ((DM_REFCOUNT, "CFilter::Release: ref=%ld\r\n", m_cRefs));
|
|
if (::InterlockedDecrement (&m_cRefs) == 0)
|
|
{
|
|
if (m_Type == ILS_FILTERTYPE_COMPOSITE)
|
|
{
|
|
HANDLE hEnum;
|
|
CFilter *pFilter;
|
|
|
|
// Free all the attributes
|
|
//
|
|
m_SubFilters.Enumerate (&hEnum);
|
|
while (m_SubFilters.Next (&hEnum, (VOID **) &pFilter) == NOERROR)
|
|
{
|
|
if (pFilter != NULL)
|
|
{
|
|
pFilter->Release ();
|
|
}
|
|
else
|
|
{
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_cRefs;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::AddSubFilter
|
|
|
|
Input:
|
|
pFilter: A pointer to a filter object.
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
AddSubFilter ( IIlsFilter *pFilter )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_COMPOSITE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
// Make sure we have a valid sub-filter
|
|
//
|
|
if (pFilter == NULL || ((CFilter *) pFilter)->IsBadFilter ())
|
|
return ILS_E_POINTER;
|
|
|
|
HRESULT hr = m_SubFilters.Insert ((VOID *) pFilter);
|
|
if (hr == S_OK)
|
|
m_cSubFilters++;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::RemoveSubFilter
|
|
|
|
Input:
|
|
pFilter: A placeholder to a pointer to a filter object.
|
|
If it is NULL, remove the first item.
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
RemoveSubFilter ( IIlsFilter *pFilter )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_COMPOSITE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
// Make sure we have a valid filter
|
|
//
|
|
if (pFilter == NULL || ((CFilter *) pFilter)->IsBadFilter ())
|
|
return ILS_E_POINTER;
|
|
|
|
HRESULT hr = m_SubFilters.Remove ((VOID *) pFilter);
|
|
if (hr == S_OK)
|
|
{
|
|
ASSERT (m_cSubFilters > 0);
|
|
m_cSubFilters--;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFilter::
|
|
RemoveAnySubFilter ( CFilter **ppFilter )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_COMPOSITE)
|
|
{
|
|
ASSERT (FALSE);
|
|
return ILS_E_FILTER_TYPE;
|
|
}
|
|
|
|
// Make sure we have a valid filter
|
|
//
|
|
if (ppFilter == NULL)
|
|
{
|
|
ASSERT (FALSE);
|
|
return ILS_E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if (*ppFilter == NULL)
|
|
{
|
|
HANDLE hEnum;
|
|
|
|
m_SubFilters.Enumerate (&hEnum);
|
|
m_SubFilters.Next (&hEnum, (VOID **) ppFilter);
|
|
}
|
|
|
|
hr = m_SubFilters.Remove ((VOID *) *ppFilter);
|
|
if (hr == S_OK)
|
|
{
|
|
ASSERT (m_cSubFilters > 0);
|
|
m_cSubFilters--;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::GetCount
|
|
|
|
Output:
|
|
pcElements: A pointer to the count of filter elements.
|
|
|
|
History:
|
|
12/03/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
GetCount ( ULONG *pcElements )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_COMPOSITE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
HRESULT hr = S_OK;
|
|
if (pcElements != NULL)
|
|
{
|
|
*pcElements = m_cSubFilters;
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_POINTER;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::CalcFilterSize
|
|
|
|
Input/Output:
|
|
pcbStringSize: A pointer to the cumulative string size.
|
|
|
|
History:
|
|
12/03/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
HRESULT CFilter::
|
|
CalcFilterSize ( ULONG *pcbStringSize )
|
|
{
|
|
ASSERT (pcbStringSize != NULL);
|
|
|
|
HRESULT hr = S_OK;
|
|
ULONG cbSize;
|
|
TCHAR *psz;
|
|
|
|
switch (m_Type)
|
|
{
|
|
case ILS_FILTERTYPE_COMPOSITE:
|
|
{
|
|
// First, count for "()"
|
|
//
|
|
cbSize = 4 * sizeof (TCHAR); // "(&)"
|
|
|
|
// Second, enumerat every child
|
|
//
|
|
HANDLE hEnum;
|
|
CFilter *pFilter = NULL;
|
|
m_SubFilters.Enumerate (&hEnum);
|
|
while (m_SubFilters.Next (&hEnum, (VOID **) &pFilter) == NOERROR)
|
|
{
|
|
if (pFilter != NULL)
|
|
{
|
|
hr = pFilter->CalcFilterSize (pcbStringSize);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (FALSE);
|
|
hr = ILS_E_POINTER;
|
|
}
|
|
|
|
// Report error if needed
|
|
//
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
} // while
|
|
} // case
|
|
break;
|
|
|
|
case ILS_FILTERTYPE_SIMPLE:
|
|
{
|
|
// First, count for "()"
|
|
//
|
|
cbSize = 3 * sizeof (TCHAR); // "()"
|
|
|
|
// Second, count for attribute name
|
|
//
|
|
ASSERT (m_NameType == ILS_ATTRNAME_STANDARD || m_NameType == ILS_ATTRNAME_ARBITRARY);
|
|
psz = (m_NameType == ILS_ATTRNAME_STANDARD) ?
|
|
(TCHAR *) UlsLdap_GetStdAttrNameString (m_Name.std) :
|
|
m_Name.psz;
|
|
if (psz == NULL)
|
|
{
|
|
hr = ILS_E_POINTER;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Add up the string length
|
|
//
|
|
cbSize += lstrlen (psz) * sizeof (TCHAR);
|
|
|
|
// Third, add up the equal sign, eg. "~="
|
|
//
|
|
cbSize += sizeof (TCHAR) * 2;
|
|
|
|
// Fourth, count for attribute value
|
|
//
|
|
psz = m_pszValue;
|
|
if (psz != NULL)
|
|
{
|
|
cbSize += lstrlen (psz) * sizeof (TCHAR);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
hr = ILS_E_FILTER_TYPE;
|
|
break;
|
|
}
|
|
|
|
MyExit:
|
|
|
|
// Clean up the size if failed
|
|
//
|
|
if (hr != S_OK)
|
|
cbSize = 0;
|
|
|
|
// Output the string size
|
|
//
|
|
*pcbStringSize += cbSize;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::BuildLdapString
|
|
|
|
Input/Output:
|
|
ppszBuf: a pointer to where the next char of the rendering buffer is.
|
|
|
|
History:
|
|
12/03/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
HRESULT CFilter::
|
|
BuildLdapString ( TCHAR **ppszBuf )
|
|
{
|
|
ASSERT (ppszBuf != NULL);
|
|
|
|
// A running pointer
|
|
//
|
|
TCHAR *pszCurr = *ppszBuf;
|
|
HRESULT hr = S_OK;
|
|
|
|
// First, output "("
|
|
//
|
|
*pszCurr++ = TEXT ('(');
|
|
|
|
// Second, output the operator if composite;
|
|
// output the attribute name if simple
|
|
//
|
|
switch (m_Type)
|
|
{
|
|
case ILS_FILTERTYPE_COMPOSITE:
|
|
{
|
|
// Second, Output the operator
|
|
//
|
|
switch (GetOp ())
|
|
{
|
|
case ILS_FILTEROP_AND:
|
|
*pszCurr++ = TEXT ('&');
|
|
break;
|
|
case ILS_FILTEROP_OR:
|
|
*pszCurr++ = TEXT ('|');
|
|
break;
|
|
case ILS_FILTEROP_NOT:
|
|
*pszCurr++ = TEXT ('!');
|
|
break;
|
|
default:
|
|
hr = ILS_E_PARAMETER;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Third, enumerate every child
|
|
//
|
|
HANDLE hEnum;
|
|
CFilter *pFilter;
|
|
m_SubFilters.Enumerate (&hEnum);
|
|
while (m_SubFilters.Next (&hEnum, (VOID **) &pFilter) == NOERROR)
|
|
{
|
|
if (pFilter != NULL)
|
|
{
|
|
hr = pFilter->BuildLdapString (&pszCurr);
|
|
}
|
|
else
|
|
{
|
|
ASSERT (FALSE);
|
|
hr = ILS_E_POINTER;
|
|
}
|
|
|
|
// Report error if needed
|
|
//
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
} // while
|
|
} // case
|
|
break;
|
|
|
|
case ILS_FILTERTYPE_SIMPLE:
|
|
{
|
|
// Second, output attribute name
|
|
//
|
|
ASSERT (m_NameType == ILS_ATTRNAME_STANDARD || m_NameType == ILS_ATTRNAME_ARBITRARY);
|
|
TCHAR *psz = (m_NameType == ILS_ATTRNAME_STANDARD) ?
|
|
(TCHAR *) UlsLdap_GetStdAttrNameString (m_Name.std) :
|
|
m_Name.psz;
|
|
|
|
// Copy the attribute name
|
|
//
|
|
lstrcpy (pszCurr, psz);
|
|
pszCurr += lstrlen (pszCurr);
|
|
|
|
// Third, copy the comparison sign
|
|
//
|
|
switch (GetOp ())
|
|
{
|
|
case ILS_FILTEROP_EQUAL:
|
|
*pszCurr++ = TEXT ('=');
|
|
break;
|
|
case ILS_FILTEROP_EXIST:
|
|
*pszCurr++ = TEXT ('=');
|
|
*pszCurr++ = TEXT ('*');
|
|
break;
|
|
case ILS_FILTEROP_APPROX:
|
|
*pszCurr++ = TEXT ('~');
|
|
*pszCurr++ = TEXT ('=');
|
|
break;
|
|
case ILS_FILTEROP_LESS_THAN:
|
|
*pszCurr++ = TEXT ('<');
|
|
*pszCurr++ = TEXT ('=');
|
|
break;
|
|
case ILS_FILTEROP_GREATER_THAN:
|
|
*pszCurr++ = TEXT ('>');
|
|
*pszCurr++ = TEXT ('=');
|
|
break;
|
|
default:
|
|
ASSERT (FALSE);
|
|
hr = ILS_E_PARAMETER;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Fourth, count for attribute value
|
|
//
|
|
psz = m_pszValue;
|
|
if (psz != NULL)
|
|
{
|
|
lstrcpy (pszCurr, psz);
|
|
pszCurr += lstrlen (pszCurr);
|
|
}
|
|
} // case
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
hr = ILS_E_FILTER_TYPE;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Finally, output ")"
|
|
//
|
|
*pszCurr++ = TEXT (')');
|
|
|
|
MyExit:
|
|
|
|
// Output where the next char should go
|
|
//
|
|
*pszCurr = TEXT ('\0');
|
|
*ppszBuf = pszCurr;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::SetStandardAttributeName
|
|
|
|
Input:
|
|
AttrName: An index to identify a standard attribute name.
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
SetStandardAttributeName ( ILS_STD_ATTR_NAME AttrName )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_SIMPLE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
// Check standard attributes
|
|
//
|
|
if (((LONG) AttrName <= (LONG) ILS_STDATTR_NULL) ||
|
|
((LONG) AttrName >= (LONG) ILS_NUM_OF_STDATTRS))
|
|
return ILS_E_PARAMETER;
|
|
|
|
// Free up the old string if needed
|
|
//
|
|
FreeName ();
|
|
|
|
// Set the new standard attribute name
|
|
//
|
|
m_NameType = ILS_ATTRNAME_STANDARD;
|
|
m_Name.std = AttrName;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::SetExtendedAttributeName
|
|
|
|
Input:
|
|
pszAnyAttrName: A pointer to the name of an arbitrary attribute.
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
SetExtendedAttributeName ( BSTR bstrAnyAttrName )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_SIMPLE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
// Make sure the string is valid
|
|
//
|
|
if (bstrAnyAttrName == NULL)
|
|
return ILS_E_POINTER;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
#ifdef _UNICODE
|
|
hr = SetExtendedAttributeName ((WCHAR *) bstrAnyAttrName);
|
|
#else
|
|
TCHAR *pszAnyAttrName = NULL;
|
|
hr = BSTR_to_LPTSTR (&pszAnyAttrName, bstrAnyAttrName);
|
|
if (hr == S_OK)
|
|
{
|
|
ASSERT (pszAnyAttrName != NULL);
|
|
hr = SetExtendedAttributeName (pszAnyAttrName);
|
|
::MemFree(pszAnyAttrName);
|
|
}
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFilter::
|
|
SetExtendedAttributeName ( TCHAR *pszAnyAttrName )
|
|
{
|
|
ASSERT (pszAnyAttrName != NULL);
|
|
|
|
// Set the new standard attribute name
|
|
//
|
|
HRESULT hr = S_OK;
|
|
const TCHAR *pszPrefix = UlsLdap_GetExtAttrNamePrefix ();
|
|
ULONG cchPrefix = (pszPrefix != NULL) ? lstrlen (pszPrefix) : 0; // don't put +1 here!!!
|
|
TCHAR *psz = (TCHAR *) MemAlloc ((lstrlen (pszAnyAttrName) + 1 + cchPrefix) * sizeof (TCHAR));
|
|
if (psz != NULL)
|
|
{
|
|
FreeName ();
|
|
m_NameType = ILS_ATTRNAME_ARBITRARY;
|
|
m_Name.psz = psz;
|
|
if (pszPrefix != NULL)
|
|
{
|
|
lstrcpy (psz, pszPrefix);
|
|
psz += cchPrefix;
|
|
}
|
|
lstrcpy (psz, pszAnyAttrName);
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::SetAttributeValue
|
|
|
|
Input:
|
|
pszAttrValue: A pointer to the string value of an attribute.
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
STDMETHODIMP CFilter::
|
|
SetAttributeValue ( BSTR bstrAttrValue )
|
|
{
|
|
// Make sure we have correct filter type
|
|
//
|
|
if (m_Type != ILS_FILTERTYPE_SIMPLE)
|
|
return ILS_E_FILTER_TYPE;
|
|
|
|
// Make sure we have valid string
|
|
//
|
|
if (bstrAttrValue == NULL)
|
|
return ILS_E_POINTER;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
#ifdef _UNICODE
|
|
hr = SetAttributeValue ((WCHAR *) bstrAttrValue);
|
|
#else
|
|
TCHAR *pszAttrValue = NULL;
|
|
hr = BSTR_to_LPTSTR (&pszAttrValue, bstrAttrValue);
|
|
if (hr == S_OK)
|
|
{
|
|
ASSERT (pszAttrValue != NULL);
|
|
hr = SetAttributeValue (pszAttrValue);
|
|
::MemFree(pszAttrValue);
|
|
}
|
|
#endif
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFilter::
|
|
SetAttributeValue ( TCHAR *pszAttrValue )
|
|
{
|
|
ASSERT (pszAttrValue != NULL);
|
|
|
|
// Make a duplicate of the attribute value
|
|
//
|
|
HRESULT hr = S_OK;
|
|
ULONG cch = My_lstrlen (pszAttrValue);
|
|
if (cch < FILTER_INTERNAL_SMALL_BUFFER_SIZE)
|
|
{
|
|
FreeValue ();
|
|
m_pszValue = &m_szInternalValueBuffer[0];
|
|
My_lstrcpy (m_pszValue, pszAttrValue);
|
|
}
|
|
else
|
|
{
|
|
TCHAR *psz = My_strdup (pszAttrValue);
|
|
if (psz != NULL)
|
|
{
|
|
FreeValue ();
|
|
m_pszValue = psz;
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::FreeName
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
VOID CFilter::
|
|
FreeName ( VOID )
|
|
{
|
|
ASSERT (m_Type == ILS_FILTERTYPE_SIMPLE);
|
|
|
|
// Free the value field
|
|
//
|
|
if (m_NameType == ILS_ATTRNAME_ARBITRARY)
|
|
{
|
|
MemFree (m_Name.psz);
|
|
}
|
|
|
|
// Reset it to zero
|
|
//
|
|
ZeroMemory (&m_Name, sizeof (m_Name));
|
|
|
|
// Reset name type
|
|
//
|
|
m_NameType = ILS_ATTRNAME_UNKNOWN;
|
|
}
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
CFilter::FreeValue
|
|
|
|
History:
|
|
11/12/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
---------------------------------------------------------------------- */
|
|
|
|
VOID CFilter::
|
|
FreeValue ( VOID )
|
|
{
|
|
ASSERT (m_Type == ILS_FILTERTYPE_SIMPLE);
|
|
|
|
// Free the value field
|
|
//
|
|
if (m_pszValue != &m_szInternalValueBuffer[0])
|
|
{
|
|
MemFree (m_pszValue);
|
|
}
|
|
|
|
m_pszValue = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
CFilterParser::CFilterParser ( VOID )
|
|
:
|
|
m_pszFilter (NULL),
|
|
m_pszCurr (NULL),
|
|
m_TokenType (ILS_TOKEN_NULL),
|
|
m_pszTokenValue (NULL),
|
|
m_nTokenValue (0)
|
|
{
|
|
}
|
|
|
|
|
|
CFilterParser::~CFilterParser ( VOID )
|
|
{
|
|
::MemFree(m_pszFilter);
|
|
}
|
|
|
|
|
|
HRESULT CFilterParser::
|
|
Expr ( CFilter **ppOutFilter, TCHAR *pszFilter )
|
|
{
|
|
// Make sure we have a valid string
|
|
//
|
|
if (ppOutFilter == NULL || pszFilter == NULL)
|
|
return ILS_E_POINTER;
|
|
|
|
// Free old string if any
|
|
//
|
|
MemFree (m_pszFilter); // checking null inside
|
|
|
|
// Find out how big the filter string
|
|
//
|
|
ULONG cch = lstrlen (pszFilter) + 1;
|
|
if (cch < 32)
|
|
cch = 32; // make sure we have some decent size of buffer
|
|
|
|
// Allocate buffer to keep the filter string
|
|
//
|
|
m_pszFilter = (TCHAR *) MemAlloc (cch * sizeof (TCHAR) * 2);
|
|
if (m_pszFilter == NULL)
|
|
return ILS_E_MEMORY;
|
|
|
|
// Copy filter string
|
|
//
|
|
lstrcpy (m_pszFilter, pszFilter);
|
|
m_pszCurr = m_pszFilter;
|
|
|
|
// Keep the rest for token value
|
|
//
|
|
m_pszTokenValue = m_pszFilter + cch;
|
|
m_nTokenValue = 0;
|
|
|
|
// Call the parser engine
|
|
//
|
|
return Expr (ppOutFilter);
|
|
}
|
|
|
|
|
|
HRESULT CFilterParser::
|
|
Expr ( CFilter **ppOutFilter )
|
|
{
|
|
/* LR(1) Parsing Grammar
|
|
<Expr> := '(' <Expr> ')' <TailExpr> |
|
|
'!' '(' Expr ')' |
|
|
AttrName EqualOp AttrValue <TailExpr> |
|
|
NULL
|
|
<TailExpr> := RelOp Expr | NULL
|
|
EqualOp := '!=' | '='
|
|
RelOp := '&' | '|' | '!'
|
|
AttrName := '$' Integer | Alphanum
|
|
AttrValue := Alphanum
|
|
*/
|
|
|
|
// Clean up first
|
|
//
|
|
ASSERT (ppOutFilter != NULL);
|
|
*ppOutFilter = NULL;
|
|
HRESULT hr = S_OK;
|
|
CFilter *pElement = NULL;
|
|
|
|
// Look ahead by 1
|
|
//
|
|
GetToken ();
|
|
switch (m_TokenType)
|
|
{
|
|
case ILS_TOKEN_NOT:
|
|
// Make sure left parenthesis
|
|
//
|
|
GetToken ();
|
|
if (m_TokenType != ILS_TOKEN_LP)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Fall through
|
|
//
|
|
|
|
case ILS_TOKEN_LP:
|
|
// Parse the expression inside parentheses
|
|
//
|
|
hr = Expr (ppOutFilter);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
|
|
// See if it is incomplete expr
|
|
//
|
|
if (*ppOutFilter == NULL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Make sure right parenthesis ended
|
|
// ILS_TOKEN_RP was taken in TrailExpr()
|
|
//
|
|
if (m_TokenType != ILS_TOKEN_RP)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Handle TailExpr
|
|
//
|
|
hr = TailExpr (ppOutFilter, *ppOutFilter);
|
|
break;
|
|
|
|
case ILS_TOKEN_STDATTR:
|
|
case ILS_TOKEN_LITERAL:
|
|
// Create a simple filter
|
|
//
|
|
pElement = new CFilter (ILS_FILTERTYPE_SIMPLE);
|
|
if (pElement == NULL)
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
pElement->AddRef ();
|
|
|
|
// Set arbitrary attribute name
|
|
//
|
|
hr = (m_TokenType == ILS_TOKEN_STDATTR) ?
|
|
pElement->SetStandardAttributeName ((ILS_STD_ATTR_NAME) m_nTokenValue) :
|
|
pElement->SetExtendedAttributeName (m_pszTokenValue);
|
|
if (hr != S_OK)
|
|
{
|
|
goto MyExit;
|
|
}
|
|
|
|
// Must be eq or neq
|
|
//
|
|
GetToken ();
|
|
switch (m_TokenType)
|
|
{
|
|
case ILS_TOKEN_EQ:
|
|
case ILS_TOKEN_NEQ:
|
|
pElement->SetOp ((ILS_FILTER_OP) m_nTokenValue);
|
|
break;
|
|
default:
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Must be literal attribute value
|
|
//
|
|
GetToken ();
|
|
if (m_TokenType != ILS_TOKEN_LITERAL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
hr = pElement->SetAttributeValue (m_pszTokenValue);
|
|
|
|
// Handle TailExpr
|
|
//
|
|
hr = TailExpr (ppOutFilter, pElement);
|
|
break;
|
|
|
|
case ILS_TOKEN_NULL:
|
|
break;
|
|
|
|
default:
|
|
hr = ILS_E_FILTER_STRING;
|
|
break;
|
|
}
|
|
|
|
MyExit:
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
if (pElement != NULL)
|
|
pElement->Release ();
|
|
|
|
if (*ppOutFilter != NULL)
|
|
(*ppOutFilter)->Release ();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFilterParser::
|
|
TailExpr ( CFilter **ppOutFilter, CFilter *pInFilter )
|
|
{
|
|
// Clean up first
|
|
//
|
|
ASSERT (ppOutFilter != NULL);
|
|
ASSERT (pInFilter != NULL);
|
|
*ppOutFilter = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Look ahead
|
|
//
|
|
ILS_FILTER_OP FilterOp = ILS_FILTEROP_OR;
|
|
GetToken ();
|
|
switch (m_TokenType)
|
|
{
|
|
case ILS_TOKEN_AND:
|
|
// Change filter op to AND
|
|
//
|
|
FilterOp = ILS_FILTEROP_AND;
|
|
|
|
// Fall through
|
|
//
|
|
|
|
case ILS_TOKEN_OR:
|
|
// Assume FilterOp is set properly
|
|
//
|
|
ASSERT (FilterOp == ILS_FILTEROP_OR ||
|
|
FilterOp == ILS_FILTEROP_AND);
|
|
|
|
// Parse the expr
|
|
//
|
|
hr = Expr (ppOutFilter);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
|
|
// See if it is incomplete expr
|
|
//
|
|
if (*ppOutFilter == NULL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// If the out filter is a composite and has same op,
|
|
// then re-use the composite
|
|
// else create a new composite
|
|
//
|
|
if ((*ppOutFilter)->GetType () == ILS_FILTERTYPE_COMPOSITE &&
|
|
(*ppOutFilter)->GetOp () == FilterOp)
|
|
{
|
|
// Re-use the composite
|
|
//
|
|
hr = ((CFilter *) (*ppOutFilter))->AddSubFilter (pInFilter);
|
|
if (hr != S_OK)
|
|
{
|
|
goto MyExit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Create a container for in filter and new filter from Expr
|
|
//
|
|
CFilter *pFilter = new CFilter (ILS_FILTERTYPE_COMPOSITE);
|
|
if (pFilter == NULL)
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
pFilter->AddRef ();
|
|
|
|
// Set op
|
|
//
|
|
pFilter->SetOp (FilterOp);
|
|
|
|
// Set up membership
|
|
//
|
|
hr = pFilter->AddSubFilter (*ppOutFilter);
|
|
if (hr != S_OK)
|
|
{
|
|
pFilter->Release ();
|
|
goto MyExit;
|
|
}
|
|
hr = pFilter->AddSubFilter (pInFilter);
|
|
if (hr != S_OK)
|
|
{
|
|
pFilter->Release (); // recursively
|
|
*ppOutFilter = NULL;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Output this new composite filter
|
|
//
|
|
*ppOutFilter = pFilter;
|
|
}
|
|
break;
|
|
|
|
case ILS_TOKEN_NOT:
|
|
// Should not have in filter at all
|
|
//
|
|
if (pInFilter != NULL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Parse the expr
|
|
//
|
|
hr = Expr (ppOutFilter);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
|
|
// If it is incomplete expr
|
|
//
|
|
if (*ppOutFilter == NULL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// If the out filter is a composite and has same op,
|
|
// then re-use the composite
|
|
// else create a new composite
|
|
//
|
|
if ((*ppOutFilter)->GetType () == ILS_FILTERTYPE_COMPOSITE &&
|
|
(*ppOutFilter)->GetOp () == ILS_FILTEROP_NOT)
|
|
{
|
|
// Remove the composite due to NOT NOT cancellation
|
|
//
|
|
CFilter *pFilter = NULL;
|
|
hr = (*ppOutFilter)->RemoveAnySubFilter (&pFilter);
|
|
if (hr != S_OK)
|
|
{
|
|
goto MyExit;
|
|
}
|
|
|
|
// Make sure we have a valid pFilter
|
|
//
|
|
if (pFilter == NULL)
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Free the old out filter
|
|
//
|
|
(*ppOutFilter)->Release ();
|
|
|
|
// Output this filter
|
|
//
|
|
*ppOutFilter = pFilter;
|
|
}
|
|
else
|
|
{
|
|
// Create a container for in filter and new filter from Expr
|
|
//
|
|
CFilter *pFilter = new CFilter (ILS_FILTERTYPE_COMPOSITE);
|
|
if (pFilter == NULL)
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
pFilter->AddRef ();
|
|
|
|
// Set op
|
|
//
|
|
pFilter->SetOp (ILS_FILTEROP_NOT);
|
|
|
|
// Set up membership
|
|
//
|
|
hr = pFilter->AddSubFilter (*ppOutFilter);
|
|
if (hr != S_OK)
|
|
{
|
|
pFilter->Release ();
|
|
goto MyExit;
|
|
}
|
|
|
|
// Output this new composite filter
|
|
//
|
|
*ppOutFilter = pFilter;
|
|
}
|
|
break;
|
|
|
|
case ILS_TOKEN_NULL:
|
|
case ILS_TOKEN_RP:
|
|
// No more expression, in filter is the out filter
|
|
//
|
|
*ppOutFilter = pInFilter;
|
|
break;
|
|
|
|
default:
|
|
hr = ILS_E_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
MyExit:
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
if (*ppOutFilter != NULL)
|
|
(*ppOutFilter)->Release ();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFilterParser::
|
|
GetToken ( VOID )
|
|
{
|
|
// Set m_TokenType, m_pszTokenValue, m_nTokenValue
|
|
TCHAR *psz;
|
|
|
|
// Clean token
|
|
//
|
|
ASSERT (m_pszTokenValue != NULL);
|
|
m_TokenType = ILS_TOKEN_NULL;
|
|
*m_pszTokenValue = TEXT ('\0');
|
|
m_nTokenValue = 0;
|
|
|
|
// Have we finished?
|
|
//
|
|
if (m_pszCurr == NULL)
|
|
return S_OK;
|
|
|
|
// Skip any while spaces
|
|
//
|
|
while (::My_isspace (*m_pszCurr))
|
|
m_pszCurr++;
|
|
|
|
// Have we finished?
|
|
//
|
|
if (*m_pszCurr == TEXT ('\0'))
|
|
return S_OK;
|
|
|
|
// Look at the first character
|
|
//
|
|
HRESULT hr = S_OK;
|
|
switch ((ILS_TOKEN_TYPE) *m_pszCurr)
|
|
{
|
|
case ILS_TOKEN_STDATTR:
|
|
// Set token type
|
|
//
|
|
m_TokenType = ILS_TOKEN_STDATTR;
|
|
|
|
// Set token string
|
|
//
|
|
psz = m_pszTokenValue;
|
|
*psz++ = *m_pszCurr++;
|
|
while (*m_pszCurr != TEXT ('\0'))
|
|
{
|
|
if (TEXT ('0') <= *m_pszCurr && *m_pszCurr <= TEXT ('9'))
|
|
*psz++ = *m_pszCurr++;
|
|
else
|
|
break;
|
|
}
|
|
*psz = TEXT ('\0');
|
|
|
|
// Set token value
|
|
//
|
|
m_nTokenValue = ::GetStringLong (m_pszTokenValue + 1);
|
|
break;
|
|
|
|
case ILS_TOKEN_LP:
|
|
case ILS_TOKEN_RP:
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr++;
|
|
break;
|
|
|
|
case ILS_TOKEN_EQ:
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_EQUAL;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr++;
|
|
break;
|
|
|
|
case ILS_TOKEN_APPROX:
|
|
if (m_pszCurr[1] == TEXT ('='))
|
|
{
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_APPROX;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr;
|
|
m_pszCurr += 2;
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
}
|
|
break;
|
|
|
|
case ILS_TOKEN_GE:
|
|
if (m_pszCurr[1] == TEXT ('='))
|
|
{
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_GREATER_THAN;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr;
|
|
m_pszCurr += 2;
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
}
|
|
break;
|
|
|
|
case ILS_TOKEN_LE:
|
|
if (m_pszCurr[1] == TEXT ('='))
|
|
{
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_LESS_THAN;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr;
|
|
m_pszCurr += 2;
|
|
}
|
|
else
|
|
{
|
|
hr = ILS_E_FILTER_STRING;
|
|
}
|
|
break;
|
|
|
|
case ILS_TOKEN_AND:
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_AND;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr++;
|
|
break;
|
|
|
|
case ILS_TOKEN_OR:
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_OR;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr++;
|
|
break;
|
|
|
|
case ILS_TOKEN_NOT:
|
|
// Look ahead for !=
|
|
//
|
|
if ((ILS_TOKEN_TYPE) *(m_pszCurr+1) == TEXT ('='))
|
|
{
|
|
// Set token type
|
|
//
|
|
m_TokenType = ILS_TOKEN_NEQ;
|
|
m_pszCurr += 2;
|
|
}
|
|
else
|
|
{
|
|
// Set token value to be filter op
|
|
//
|
|
m_nTokenValue = (LONG) ILS_FILTEROP_NOT;
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (ILS_TOKEN_TYPE) *m_pszCurr++;
|
|
}
|
|
break;
|
|
|
|
default: // Handle alpha numeric
|
|
{
|
|
// Set token string
|
|
//
|
|
BOOL fStayInLoop = (*m_pszCurr != TEXT ('\0'));
|
|
psz = m_pszTokenValue;
|
|
while (fStayInLoop)
|
|
{
|
|
// Stop only when encountering delimiters such as
|
|
//
|
|
switch (*m_pszCurr)
|
|
{
|
|
case ILS_TOKEN_STDATTR:
|
|
case ILS_TOKEN_LP:
|
|
case ILS_TOKEN_RP:
|
|
case ILS_TOKEN_EQ:
|
|
// case ILS_TOKEN_NEQ: // - is a valid char such as in ms-netmeeting
|
|
case ILS_TOKEN_APPROX:
|
|
case ILS_TOKEN_GE:
|
|
case ILS_TOKEN_LE:
|
|
case ILS_TOKEN_AND:
|
|
case ILS_TOKEN_OR:
|
|
case ILS_TOKEN_NOT:
|
|
fStayInLoop = FALSE;
|
|
break;
|
|
default:
|
|
*psz++ = *m_pszCurr++;
|
|
fStayInLoop = (*m_pszCurr != TEXT ('\0'));
|
|
break;
|
|
}
|
|
}
|
|
*psz = TEXT ('\0');
|
|
|
|
// Remove trailing spaces
|
|
//
|
|
psz--;
|
|
while (psz >= m_pszCurr && ::My_isspace (*psz))
|
|
*psz-- = TEXT ('\0');
|
|
|
|
// Set token type
|
|
//
|
|
m_TokenType = (*m_pszTokenValue == TEXT ('\0')) ?
|
|
ILS_TOKEN_NULL :
|
|
ILS_TOKEN_LITERAL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT FilterToLdapString ( CFilter *pFilter, TCHAR **ppszFilter )
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Make sure we have valid pointers
|
|
//
|
|
if (pFilter == NULL || ppszFilter == NULL)
|
|
return ILS_E_POINTER;
|
|
|
|
// Clean up output
|
|
//
|
|
TCHAR *pszFilter = NULL;
|
|
|
|
// Calculate the string size
|
|
//
|
|
ULONG cbSize = 0;
|
|
hr = pFilter->CalcFilterSize (&cbSize);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
|
|
// Allocate string buffer
|
|
//
|
|
pszFilter = (TCHAR *) MemAlloc (cbSize);
|
|
if (pszFilter == NULL)
|
|
{
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Make a copy of pszFilter because
|
|
// FilterToLdapString() will change the value
|
|
//
|
|
TCHAR *pszFilterAux;
|
|
pszFilterAux = pszFilter;
|
|
|
|
// Render the filter string
|
|
//
|
|
hr = pFilter->BuildLdapString (&pszFilterAux);
|
|
|
|
MyExit:
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
MemFree (pszFilter);
|
|
pszFilter = NULL;
|
|
}
|
|
|
|
*ppszFilter = pszFilter;
|
|
return hr;
|
|
}
|
|
|