214 lines
4.5 KiB
C++
214 lines
4.5 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1999, Microsoft Corp. All rights reserved.
|
|
//
|
|
// FILE
|
|
//
|
|
// realm.cpp
|
|
//
|
|
// SYNOPSIS
|
|
//
|
|
// Defines the class Realms.
|
|
//
|
|
// MODIFICATION HISTORY
|
|
//
|
|
// 09/08/1998 Original version.
|
|
// 03/03/1999 Rewritten to use the VBScript RegExp object.
|
|
// 01/25/2000 Handle case where identity maps to an empty string.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <ias.h>
|
|
#include <memory>
|
|
|
|
#include <realm.h>
|
|
|
|
inline Realms::Rule::Rule() throw ()
|
|
: replace(NULL)
|
|
{ }
|
|
|
|
inline Realms::Rule::~Rule() throw ()
|
|
{
|
|
SysFreeString(replace);
|
|
}
|
|
|
|
Realms::Realms() throw ()
|
|
: begin(NULL), end(NULL)
|
|
{ }
|
|
|
|
Realms::~Realms() throw ()
|
|
{
|
|
delete[] begin;
|
|
}
|
|
|
|
HRESULT Realms::setRealms(VARIANT* pValue)
|
|
{
|
|
// If the VARIANT is empty, we clear the realms list and return.
|
|
if (pValue == NULL || V_VT(pValue) == VT_EMPTY)
|
|
{
|
|
setRules(NULL, 0);
|
|
return S_OK;
|
|
}
|
|
|
|
// It must be a SAFEARRAY of VARIANTs.
|
|
if (V_VT(pValue) != (VT_VARIANT | VT_ARRAY))
|
|
{ return DISP_E_TYPEMISMATCH; }
|
|
|
|
// It must be non-NULL.
|
|
LPSAFEARRAY psa = V_ARRAY(pValue);
|
|
if (psa == NULL) { return E_POINTER; }
|
|
|
|
// It must be a one-dimensional array with an even number of elements.
|
|
if (psa->cDims != 1 || (psa->rgsabound[0].cElements % 2) != 0)
|
|
{ return E_INVALIDARG; }
|
|
|
|
// Allocate a temporary array of Rules.
|
|
size_t nelem = psa->rgsabound[0].cElements / 2;
|
|
Rule* tmp = new (std::nothrow) Rule[nelem];
|
|
if (tmp == NULL) { return E_OUTOFMEMORY; }
|
|
|
|
// Iterate through the vector and construct the rules.
|
|
VARIANT* v = (VARIANT*)psa->pvData;
|
|
VARIANT* end = v + psa->rgsabound[0].cElements;
|
|
Rule* dst = tmp;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
while (v != end)
|
|
{
|
|
// Get the find string ...
|
|
if (V_VT(v) != VT_BSTR)
|
|
{
|
|
hr = DISP_E_TYPEMISMATCH;
|
|
break;
|
|
}
|
|
|
|
BSTR find = V_BSTR(v++);
|
|
|
|
// ... and the replace string.
|
|
if (V_VT(v) != VT_BSTR)
|
|
{
|
|
hr = DISP_E_TYPEMISMATCH;
|
|
break;
|
|
}
|
|
BSTR replace = V_BSTR(v++);
|
|
|
|
// Don't allow NULL's.
|
|
if (find == NULL || replace == NULL)
|
|
{
|
|
hr = E_POINTER;
|
|
break;
|
|
}
|
|
|
|
// Initialize the RegularExpression.
|
|
hr = dst->regexp.setIgnoreCase(TRUE);
|
|
if (FAILED(hr)) { break; }
|
|
hr = dst->regexp.setGlobal(TRUE);
|
|
if (FAILED(hr)) { break; }
|
|
hr = dst->regexp.setPattern(find);
|
|
if (FAILED(hr)) { break; }
|
|
|
|
// Save the replacement string.
|
|
dst->replace = SysAllocString(replace);
|
|
if (dst->replace == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
|
|
// Advance to the next rule.
|
|
++dst;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
setRules(tmp, nelem);
|
|
}
|
|
else
|
|
{
|
|
delete[] tmp;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT Realms::process(PCWSTR in, BSTR* out) const throw ()
|
|
{
|
|
if (out == NULL) { return E_INVALIDARG; }
|
|
*out = NULL;
|
|
|
|
// Quick short-circuit if there are no rules.
|
|
if (begin == end) { return S_OK; }
|
|
|
|
// Convert the string to a BSTR.
|
|
BSTR input = SysAllocString(in);
|
|
if (!input) { return E_OUTOFMEMORY; }
|
|
|
|
// Output is set to the new string (if any).
|
|
BSTR output = NULL;
|
|
|
|
// Status of rules processing.
|
|
HRESULT hr = S_OK;
|
|
|
|
// Acquire the shared lock.
|
|
monitor.Lock();
|
|
|
|
// Iterate through the rules.
|
|
for (Rule* r = begin; r != end; ++r)
|
|
{
|
|
// We'll first test for a match to avoid unnecessary allocation.
|
|
if (r->regexp.testBSTR(input))
|
|
{
|
|
// We have a match so, replace.
|
|
hr = r->regexp.replace(input, r->replace, &output);
|
|
if (FAILED(hr)) { break; }
|
|
|
|
// If it maps to nothing, replace returns NULL instead of an empty
|
|
// string.
|
|
if (!output)
|
|
{
|
|
output = SysAllocString(L"");
|
|
|
|
if (!output)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// The current output is the input to the next iteration.
|
|
SysFreeString(input);
|
|
input = output;
|
|
}
|
|
}
|
|
|
|
monitor.Unlock();
|
|
|
|
// If we succeeded in finding a match, ...
|
|
if (SUCCEEDED(hr) && output)
|
|
{
|
|
*out = output;
|
|
}
|
|
else
|
|
{
|
|
// Free the latest input.
|
|
SysFreeString(input);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void Realms::setRules(Rule* rules, ULONG numRules) throw ()
|
|
{
|
|
monitor.LockExclusive();
|
|
|
|
// Delete the old rules ...
|
|
delete[] begin;
|
|
|
|
// ... and save the new ones.
|
|
begin = rules;
|
|
end = begin + numRules;
|
|
|
|
monitor.Unlock();
|
|
}
|