Leaked source code of windows server 2003
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.

215 lines
4.8 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999, Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // realm.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // Defines the class Realms.
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 09/08/1998 Original version.
  16. // 03/03/1999 Rewritten to use the VBScript RegExp object.
  17. // 01/25/2000 Handle case where identity maps to an empty string.
  18. //
  19. ///////////////////////////////////////////////////////////////////////////////
  20. #include <ias.h>
  21. #include <memory>
  22. #include <realm.h>
  23. inline Realms::Rule::Rule() throw ()
  24. : replace(NULL)
  25. { }
  26. inline Realms::Rule::~Rule() throw ()
  27. {
  28. SysFreeString(replace);
  29. }
  30. Realms::Realms()
  31. : begin(NULL), end(NULL)
  32. {
  33. _com_util::CheckError(monitor.FinalConstruct());
  34. }
  35. Realms::~Realms() throw ()
  36. {
  37. delete[] begin;
  38. }
  39. HRESULT Realms::setRealms(VARIANT* pValue)
  40. {
  41. // If the VARIANT is empty, we clear the realms list and return.
  42. if (pValue == NULL || V_VT(pValue) == VT_EMPTY)
  43. {
  44. setRules(NULL, 0);
  45. return S_OK;
  46. }
  47. // It must be a SAFEARRAY of VARIANTs.
  48. if (V_VT(pValue) != (VT_VARIANT | VT_ARRAY))
  49. { return DISP_E_TYPEMISMATCH; }
  50. // It must be non-NULL.
  51. LPSAFEARRAY psa = V_ARRAY(pValue);
  52. if (psa == NULL) { return E_POINTER; }
  53. // It must be a one-dimensional array with an even number of elements.
  54. if (psa->cDims != 1 || (psa->rgsabound[0].cElements % 2) != 0)
  55. { return E_INVALIDARG; }
  56. // Allocate a temporary array of Rules.
  57. size_t nelem = psa->rgsabound[0].cElements / 2;
  58. Rule* tmp = new (std::nothrow) Rule[nelem];
  59. if (tmp == NULL) { return E_OUTOFMEMORY; }
  60. // Iterate through the vector and construct the rules.
  61. VARIANT* v = (VARIANT*)psa->pvData;
  62. VARIANT* end = v + psa->rgsabound[0].cElements;
  63. Rule* dst = tmp;
  64. HRESULT hr = S_OK;
  65. while (v != end)
  66. {
  67. // Get the find string ...
  68. if (V_VT(v) != VT_BSTR)
  69. {
  70. hr = DISP_E_TYPEMISMATCH;
  71. break;
  72. }
  73. BSTR find = V_BSTR(v++);
  74. // ... and the replace string.
  75. if (V_VT(v) != VT_BSTR)
  76. {
  77. hr = DISP_E_TYPEMISMATCH;
  78. break;
  79. }
  80. BSTR replace = V_BSTR(v++);
  81. // Don't allow NULL's.
  82. if (find == NULL || replace == NULL)
  83. {
  84. hr = E_POINTER;
  85. break;
  86. }
  87. // Initialize the RegularExpression.
  88. hr = dst->regexp.setIgnoreCase(TRUE);
  89. if (FAILED(hr)) { break; }
  90. hr = dst->regexp.setGlobal(TRUE);
  91. if (FAILED(hr)) { break; }
  92. hr = dst->regexp.setPattern(find);
  93. if (FAILED(hr)) { break; }
  94. // Save the replacement string.
  95. dst->replace = SysAllocString(replace);
  96. if (dst->replace == NULL)
  97. {
  98. hr = E_OUTOFMEMORY;
  99. break;
  100. }
  101. // Advance to the next rule.
  102. ++dst;
  103. }
  104. if (SUCCEEDED(hr))
  105. {
  106. setRules(tmp, nelem);
  107. }
  108. else
  109. {
  110. delete[] tmp;
  111. }
  112. return hr;
  113. }
  114. HRESULT Realms::process(PCWSTR in, BSTR* out) const throw ()
  115. {
  116. if (out == NULL) { return E_INVALIDARG; }
  117. *out = NULL;
  118. // Quick short-circuit if there are no rules.
  119. if (begin == end) { return S_OK; }
  120. // Convert the string to a BSTR.
  121. BSTR input = SysAllocString(in);
  122. if (!input) { return E_OUTOFMEMORY; }
  123. // Output is set to the new string (if any).
  124. BSTR output = NULL;
  125. // Status of rules processing.
  126. HRESULT hr = S_OK;
  127. // Acquire the shared lock.
  128. monitor.Lock();
  129. // Iterate through the rules.
  130. for (Rule* r = begin; r != end; ++r)
  131. {
  132. // We'll first test for a match to avoid unnecessary allocation.
  133. if (r->regexp.testBSTR(input))
  134. {
  135. // We have a match so, replace.
  136. hr = r->regexp.replace(input, r->replace, &output);
  137. if (FAILED(hr)) { break; }
  138. // If it maps to nothing, replace returns NULL instead of an empty
  139. // string.
  140. if (!output)
  141. {
  142. output = SysAllocString(L"");
  143. if (!output)
  144. {
  145. hr = E_OUTOFMEMORY;
  146. break;
  147. }
  148. }
  149. // The current output is the input to the next iteration.
  150. SysFreeString(input);
  151. input = output;
  152. }
  153. }
  154. monitor.Unlock();
  155. // If we succeeded in finding a match, ...
  156. if (SUCCEEDED(hr) && output)
  157. {
  158. *out = output;
  159. }
  160. else
  161. {
  162. // Free the latest input.
  163. SysFreeString(input);
  164. }
  165. return hr;
  166. }
  167. void Realms::setRules(Rule* rules, ULONG numRules) throw ()
  168. {
  169. monitor.LockExclusive();
  170. // Delete the old rules ...
  171. delete[] begin;
  172. // ... and save the new ones.
  173. begin = rules;
  174. end = begin + numRules;
  175. monitor.Unlock();
  176. }