Source code of Windows XP (NT5)
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.

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