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.

262 lines
6.7 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class RegularExpression.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include <ias.h>
  11. #include <regex.h>
  12. #include <re55.h>
  13. ///////////////////////////////////////////////////////////////////////////////
  14. //
  15. // CLASS
  16. //
  17. // FastCoCreator
  18. //
  19. // DESCRIPTION
  20. //
  21. // Wraps a class factory to allow instances of a particular coclass to
  22. // be created 'fast'.
  23. //
  24. ///////////////////////////////////////////////////////////////////////////////
  25. class FastCoCreator
  26. {
  27. public:
  28. FastCoCreator(REFCLSID rclsid, DWORD dwClsContext) throw ();
  29. ~FastCoCreator() throw ();
  30. HRESULT createInstance(
  31. LPUNKNOWN pUnkOuter,
  32. REFIID riid,
  33. LPVOID* ppv
  34. ) throw ();
  35. void destroyInstance(IUnknown* pUnk) throw ();
  36. protected:
  37. REFCLSID clsid;
  38. DWORD context;
  39. CRITICAL_SECTION monitor;
  40. ULONG refCount;
  41. IClassFactory* factory;
  42. private:
  43. FastCoCreator(FastCoCreator&) throw ();
  44. FastCoCreator& operator=(FastCoCreator&) throw ();
  45. };
  46. FastCoCreator::FastCoCreator(REFCLSID rclsid, DWORD dwClsContext)
  47. : clsid(rclsid),
  48. context(dwClsContext),
  49. refCount(0),
  50. factory(NULL)
  51. {
  52. InitializeCriticalSection(&monitor);
  53. }
  54. FastCoCreator::~FastCoCreator() throw ()
  55. {
  56. if (factory) { factory->Release(); }
  57. DeleteCriticalSection(&monitor);
  58. }
  59. HRESULT FastCoCreator::createInstance(
  60. LPUNKNOWN pUnkOuter,
  61. REFIID riid,
  62. LPVOID* ppv
  63. ) throw ()
  64. {
  65. HRESULT hr;
  66. EnterCriticalSection(&monitor);
  67. // Get a new class factory if necessary.
  68. if (!factory)
  69. {
  70. hr = CoGetClassObject(
  71. clsid,
  72. context,
  73. NULL,
  74. __uuidof(IClassFactory),
  75. (PVOID*)&factory
  76. );
  77. }
  78. if (factory)
  79. {
  80. hr = factory->CreateInstance(
  81. pUnkOuter,
  82. riid,
  83. ppv
  84. );
  85. if (SUCCEEDED(hr))
  86. {
  87. // We successfully created an object, so bump the ref. count.
  88. ++refCount;
  89. }
  90. else if (refCount == 0)
  91. {
  92. // Don't hang on to the factory if the ref. count is zero.
  93. factory->Release();
  94. factory = NULL;
  95. }
  96. }
  97. LeaveCriticalSection(&monitor);
  98. return hr;
  99. }
  100. void FastCoCreator::destroyInstance(IUnknown* pUnk) throw ()
  101. {
  102. if (pUnk)
  103. {
  104. EnterCriticalSection(&monitor);
  105. if (--refCount == 0)
  106. {
  107. // Last object went away, so release the class factory.
  108. factory->Release();
  109. factory = NULL;
  110. }
  111. LeaveCriticalSection(&monitor);
  112. pUnk->Release();
  113. }
  114. }
  115. /////////
  116. // Macro that ensures the internal RegExp object has been initalize.
  117. /////////
  118. #define CHECK_INIT() \
  119. { HRESULT hr = checkInit(); if (FAILED(hr)) { return hr; }}
  120. FastCoCreator RegularExpression::theCreator(
  121. __uuidof(RegExp),
  122. CLSCTX_INPROC_SERVER
  123. );
  124. RegularExpression::RegularExpression() throw ()
  125. : regex(NULL)
  126. { }
  127. RegularExpression::~RegularExpression() throw ()
  128. {
  129. theCreator.destroyInstance(regex);
  130. }
  131. HRESULT RegularExpression::setIgnoreCase(BOOL fIgnoreCase) throw ()
  132. {
  133. CHECK_INIT();
  134. return regex->put_IgnoreCase(fIgnoreCase ? VARIANT_TRUE : VARIANT_FALSE);
  135. }
  136. HRESULT RegularExpression::setGlobal(BOOL fGlobal) throw ()
  137. {
  138. CHECK_INIT();
  139. return regex->put_Global(fGlobal ? VARIANT_TRUE : VARIANT_FALSE);
  140. }
  141. HRESULT RegularExpression::setPattern(PCWSTR pszPattern) throw ()
  142. {
  143. CHECK_INIT();
  144. HRESULT hr;
  145. BSTR bstr = SysAllocString(pszPattern);
  146. if (bstr)
  147. {
  148. hr = regex->put_Pattern(bstr);
  149. SysFreeString(bstr);
  150. }
  151. else
  152. {
  153. hr = E_OUTOFMEMORY;
  154. }
  155. return hr;
  156. }
  157. HRESULT RegularExpression::replace(
  158. BSTR sourceString,
  159. BSTR replaceString,
  160. BSTR* pDestString
  161. ) const throw ()
  162. {
  163. VARIANT replace;
  164. #ifdef _X86_
  165. // The VB team accidentally released a version of IRegExp2 where the second
  166. // parameter was a VARIANT* instead of a VARIANT. As a result, they attempt
  167. // to detect at run-time which version of the interface was called. They do
  168. // this by calling IsBadReadPtr, which in turn generates an AV. To avoid
  169. // these undesirable breaks, we make sure that the first two 32-bits of the
  170. // VARIANT are valid pointer addresses. Since the parameters will look valid
  171. // for both the good and the bad version, VB defaults to the good version --
  172. // which is what we want. This bug only exists on x86, hence the ifdef.
  173. // The dummy variable is used to generate a readable address.
  174. static const void* dummy = 0;
  175. const void** p = reinterpret_cast<const void**>(&replace);
  176. p[0] = &dummy; // The VARIANT*
  177. p[1] = &dummy; // The BSTR*
  178. #endif
  179. V_VT(&replace) = VT_BSTR;
  180. V_BSTR(&replace) = replaceString;
  181. return regex->Replace(sourceString, replace, pDestString);
  182. }
  183. BOOL RegularExpression::testBSTR(BSTR sourceString) const throw ()
  184. {
  185. // Test the regular expression.
  186. VARIANT_BOOL fMatch = VARIANT_FALSE;
  187. regex->Test(sourceString, &fMatch);
  188. return fMatch;
  189. }
  190. BOOL RegularExpression::testString(PCWSTR sourceString) const throw ()
  191. {
  192. // ByteLen of the BSTR.
  193. DWORD nbyte = wcslen(sourceString) * sizeof(WCHAR);
  194. // We need room for the string, the ByteLen, and the null-terminator.
  195. PDWORD p = (PDWORD)_alloca(nbyte + sizeof(DWORD) + sizeof(WCHAR));
  196. // Store the ByteLen.
  197. *p++ = nbyte;
  198. // Copy in the sourceString.
  199. memcpy(p, sourceString, nbyte + sizeof(WCHAR));
  200. // Test the regular expression.
  201. VARIANT_BOOL fMatch = VARIANT_FALSE;
  202. regex->Test((BSTR)p, &fMatch);
  203. return fMatch;
  204. }
  205. void RegularExpression::swap(RegularExpression& obj) throw ()
  206. {
  207. IRegExp2* tmp = obj.regex;
  208. obj.regex = regex;
  209. regex = tmp;
  210. }
  211. HRESULT RegularExpression::checkInit() throw ()
  212. {
  213. // Have we already initialized?
  214. return regex ? S_OK : theCreator.createInstance(
  215. NULL,
  216. __uuidof(IRegExp2),
  217. (PVOID*)&regex
  218. );
  219. }