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.

664 lines
16 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: StringList object
  6. File: strlist.cpp
  7. Owner: DGottner
  8. This file contains the code for the implementation of the String List object.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "strlist.h"
  13. #include "MemChk.h"
  14. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  15. /*===================================================================
  16. CStringListElem::CStringListElem
  17. Constructor
  18. ===================================================================*/
  19. CStringListElem::CStringListElem()
  20. :
  21. m_fBufferInUse(FALSE),
  22. m_fAllocated(FALSE),
  23. m_pNext(NULL),
  24. m_szPointer(NULL)
  25. {
  26. }
  27. /*===================================================================
  28. CStringListElem::~CStringListElem
  29. Destructor
  30. ===================================================================*/
  31. CStringListElem::~CStringListElem()
  32. {
  33. if (m_fAllocated)
  34. delete [] m_szPointer;
  35. if (m_pNext)
  36. delete m_pNext;
  37. }
  38. /*===================================================================
  39. CStringListElem::Init
  40. Init CStringListElem
  41. Parameters
  42. szValue the string
  43. fMakeCopy if FALSE - just store the pointer
  44. lCodePage codepage to use to convert to UNICODE
  45. ===================================================================*/
  46. HRESULT CStringListElem::Init(
  47. char *szValue,
  48. BOOL fMakeCopy,
  49. UINT lCodePage)
  50. {
  51. // for now, always make a copy of the string. This is to ensure
  52. // that any string lists placed in session state via a dictionary
  53. // object do not have their elements freed from under them when
  54. // the request completes.
  55. if (1 /*fMakeCopy*/) {
  56. CMBCSToWChar convStr;
  57. HRESULT hr = S_OK;
  58. if (FAILED(hr = convStr.Init(szValue, lCodePage))) {
  59. return hr;
  60. }
  61. // now we will move the string into the elements memory. If the
  62. // converted string is bigger than the internal buffer, then
  63. // set the element's pointer to an allocated copy of the converted
  64. // string.
  65. if ((convStr.GetStringLen() + 1) > (sizeof(m_szBuffer)/sizeof(WCHAR))) {
  66. m_szPointer = convStr.GetString(TRUE);
  67. if (!m_szPointer)
  68. return E_OUTOFMEMORY;
  69. m_fBufferInUse = FALSE;
  70. m_fAllocated = TRUE;
  71. }
  72. else {
  73. // if it fits, simply copy it into the internal buffer.
  74. wcscpy(m_szBuffer, convStr.GetString());
  75. m_fBufferInUse = TRUE;
  76. m_fAllocated = FALSE;
  77. }
  78. }
  79. #if 0
  80. else {
  81. m_szPointer = szValue;
  82. m_fBufferInUse = FALSE;
  83. m_fAllocated = FALSE;
  84. }
  85. #endif
  86. m_pNext = NULL;
  87. return S_OK;
  88. }
  89. /*===================================================================
  90. CStringListElem::Init
  91. Init CStringListElem
  92. Parameters
  93. szValue the string
  94. fMakeCopy if FALSE - just store the pointer
  95. ===================================================================*/
  96. HRESULT CStringListElem::Init(
  97. WCHAR *wszValue,
  98. BOOL fMakeCopy)
  99. {
  100. // for now, always make a copy of the string. This is to ensure
  101. // that any string lists placed in session state via a dictionary
  102. // object do not have their elements freed from under them when
  103. // the request completes.
  104. if (1 /*fMakeCopy*/) {
  105. // now we will move the string into the elements memory. If the
  106. // converted string is bigger than the internal buffer, then
  107. // set the element's pointer to an allocated copy
  108. if ((wcslen(wszValue) + 1) > (sizeof(m_szBuffer)/sizeof(WCHAR))) {
  109. m_szPointer = StringDupW(wszValue);
  110. if (!m_szPointer)
  111. return E_OUTOFMEMORY;
  112. m_fBufferInUse = FALSE;
  113. m_fAllocated = TRUE;
  114. }
  115. else {
  116. // if it fits, simply copy it into the internal buffer.
  117. wcscpy(m_szBuffer, wszValue);
  118. m_fBufferInUse = TRUE;
  119. m_fAllocated = FALSE;
  120. }
  121. }
  122. #if 0
  123. else {
  124. m_szPointer = szValue;
  125. m_fBufferInUse = FALSE;
  126. m_fAllocated = FALSE;
  127. }
  128. #endif
  129. m_pNext = NULL;
  130. return S_OK;
  131. }
  132. /*===================================================================
  133. CStringList::CStringList
  134. Constructor
  135. ===================================================================*/
  136. CStringList::CStringList(IUnknown *pUnkOuter, PFNDESTROYED pfnDestroy)
  137. : m_ISupportErrImp(this, pUnkOuter, IID_IStringList)
  138. {
  139. m_pBegin = m_pEnd = NULL;
  140. m_cValues = 0;
  141. m_cRefs = 1;
  142. m_pfnDestroy = pfnDestroy;
  143. CDispatch::Init(IID_IStringList);
  144. m_lCodePage = GetACP();
  145. }
  146. /*===================================================================
  147. CStringList::~CStringList
  148. Destructor
  149. ===================================================================*/
  150. CStringList::~CStringList()
  151. {
  152. if (m_pBegin)
  153. delete m_pBegin;
  154. }
  155. /*===================================================================
  156. CStringList::AddValue
  157. Parameters:
  158. szValue - value to add to the string list
  159. lCodePage - the CodePage used when construct return value
  160. ===================================================================*/
  161. HRESULT CStringList::AddValue(char *szValue, BOOL fDuplicate, UINT lCodePage)
  162. {
  163. CStringListElem *pElem = new CStringListElem;
  164. if (!pElem)
  165. return E_OUTOFMEMORY;
  166. m_lCodePage = lCodePage;
  167. HRESULT hr = pElem->Init(szValue, fDuplicate, lCodePage);
  168. if (FAILED(hr)) {
  169. delete pElem;
  170. return hr;
  171. }
  172. if (m_pBegin == NULL)
  173. {
  174. m_pBegin = m_pEnd = pElem;
  175. }
  176. else
  177. {
  178. m_pEnd->SetNext(pElem);
  179. m_pEnd = pElem;
  180. }
  181. ++m_cValues;
  182. return S_OK;
  183. }
  184. /*===================================================================
  185. CStringList::AddValue
  186. Parameters:
  187. szValue - value to add to the string list
  188. lCodePage - the CodePage used when construct return value
  189. ===================================================================*/
  190. HRESULT CStringList::AddValue(WCHAR *szValue, BOOL fDuplicate)
  191. {
  192. CStringListElem *pElem = new CStringListElem;
  193. if (!pElem)
  194. return E_OUTOFMEMORY;
  195. HRESULT hr = pElem->Init(szValue, fDuplicate);
  196. if (FAILED(hr)) {
  197. delete pElem;
  198. return hr;
  199. }
  200. if (m_pBegin == NULL)
  201. {
  202. m_pBegin = m_pEnd = pElem;
  203. }
  204. else
  205. {
  206. m_pEnd->SetNext(pElem);
  207. m_pEnd = pElem;
  208. }
  209. ++m_cValues;
  210. return S_OK;
  211. }
  212. /*===================================================================
  213. CStringList::QueryInterface
  214. CStringList::AddRef
  215. CStringList::Release
  216. IUnknown members for CStringList object.
  217. ===================================================================*/
  218. STDMETHODIMP CStringList::QueryInterface(const IID &iid, void **ppvObj)
  219. {
  220. *ppvObj = NULL;
  221. if (iid == IID_IUnknown || iid == IID_IDispatch ||
  222. iid == IID_IStringList || iid == IID_IDenaliIntrinsic)
  223. {
  224. *ppvObj = this;
  225. }
  226. if (iid == IID_ISupportErrorInfo)
  227. *ppvObj = &m_ISupportErrImp;
  228. if (*ppvObj != NULL)
  229. {
  230. static_cast<IUnknown *>(*ppvObj)->AddRef();
  231. return S_OK;
  232. }
  233. return ResultFromScode(E_NOINTERFACE);
  234. }
  235. STDMETHODIMP_(ULONG) CStringList::AddRef()
  236. {
  237. return ++m_cRefs;
  238. }
  239. STDMETHODIMP_(ULONG) CStringList::Release()
  240. {
  241. if (--m_cRefs != 0)
  242. return m_cRefs;
  243. if (m_pfnDestroy != NULL)
  244. (*m_pfnDestroy)();
  245. delete this;
  246. return 0;
  247. }
  248. /*===================================================================
  249. CStringList::get_Count
  250. Parameters:
  251. pcValues - count is stored in *pcValues
  252. ===================================================================*/
  253. STDMETHODIMP CStringList::get_Count(int *pcValues)
  254. {
  255. *pcValues = m_cValues;
  256. return S_OK;
  257. }
  258. /*===================================================================
  259. CStringList::ConstructDefaultReturn
  260. Return comma-separated list for the case where the CStringList
  261. is not indexed.
  262. ===================================================================*/
  263. HRESULT CStringList::ConstructDefaultReturn(VARIANT *pvarOut) {
  264. VariantClear(pvarOut);
  265. //
  266. // NEW SEMANTIC: we now return Empty (and not "") if nothing is in the collection
  267. //
  268. if (m_cValues == 0)
  269. return S_OK; // VariantClear set pvarOut to Empty
  270. STACK_BUFFER( tempValues, 1024 );
  271. register CStringListElem *pElem;
  272. int cBytes = 0;
  273. for (pElem = m_pBegin; pElem != NULL; pElem = pElem->QueryNext())
  274. cBytes += (wcslen(pElem->QueryValue()) * sizeof(WCHAR));
  275. // need to account for the ", " and NULL Termination
  276. cBytes += sizeof(WCHAR) + ((2*(m_cValues - 1)) * sizeof(WCHAR));
  277. if (!tempValues.Resize(cBytes)) {
  278. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
  279. return E_FAIL;
  280. }
  281. WCHAR *szReturn = (WCHAR *)tempValues.QueryPtr();
  282. szReturn[0] = L'\0';
  283. WCHAR *szNext = szReturn;
  284. for (pElem = m_pBegin; pElem != NULL; pElem = pElem->QueryNext()) {
  285. szNext = strcpyExW(szNext, pElem->QueryValue());
  286. if (pElem->QueryNext() != NULL)
  287. szNext = strcpyExW(szNext, L", ");
  288. }
  289. BSTR bstrT;
  290. if ((bstrT = SysAllocString(szReturn)) == NULL) {
  291. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
  292. return E_FAIL;
  293. }
  294. V_VT(pvarOut) = VT_BSTR;
  295. V_BSTR(pvarOut) = bstrT;
  296. return S_OK;
  297. }
  298. /*===================================================================
  299. CStringList::get_Item
  300. ===================================================================*/
  301. STDMETHODIMP CStringList::get_Item(VARIANT varIndex, VARIANT *pvarOut)
  302. {
  303. long i;
  304. VariantInit(pvarOut);
  305. if (V_VT(&varIndex) == VT_ERROR) {
  306. return ConstructDefaultReturn(pvarOut);
  307. }
  308. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing variants
  309. // Loop through while we have a VT_BYREF until we get the real variant.
  310. //
  311. // and changed again...
  312. //
  313. // BUG 1609 the prior code was only checking for VT_I4 and jscript passed in a
  314. // VT_R8 and it failed so now we use the VariantChangeType call to solve the
  315. // problem
  316. VARIANT var;
  317. VariantInit(&var);
  318. HRESULT hr = S_OK;
  319. if((hr = VariantChangeType(&var, &varIndex ,0,VT_I4)) != S_OK) {
  320. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_EXPECTING_INT);
  321. return E_FAIL;
  322. }
  323. i = V_I4(&var);
  324. VariantClear(&var);
  325. // END bug 1609
  326. if (i <= 0 || i > m_cValues) {
  327. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_BAD_ARRAY_INDEX);
  328. return E_FAIL;
  329. }
  330. register CStringListElem *pElem = m_pBegin;
  331. while (--i > 0)
  332. pElem = pElem->QueryNext();
  333. BSTR bstrT;
  334. if ((bstrT = SysAllocString(pElem->QueryValue())) == NULL ) {
  335. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
  336. return E_FAIL;
  337. }
  338. V_VT(pvarOut) = VT_BSTR;
  339. V_BSTR(pvarOut) = bstrT;
  340. return S_OK;
  341. }
  342. /*===================================================================
  343. CStringList::get__NewEnum
  344. ===================================================================*/
  345. STDMETHODIMP CStringList::get__NewEnum(IUnknown **ppEnumReturn)
  346. {
  347. *ppEnumReturn = new CStrListIterator(this);
  348. if (*ppEnumReturn == NULL)
  349. {
  350. ExceptionId(IID_IStringList, IDE_REQUEST, IDE_OOM);
  351. return E_OUTOFMEMORY;
  352. }
  353. return S_OK;
  354. }
  355. /*------------------------------------------------------------------
  356. * C S t r L i s t I t e r a t o r
  357. */
  358. /*===================================================================
  359. CStrListIterator::CStrListIterator
  360. Constructor
  361. NOTE: CRequest is (currently) not refcounted. AddRef/Release
  362. added to protect against future changes.
  363. ===================================================================*/
  364. CStrListIterator::CStrListIterator(CStringList *pStrings)
  365. {
  366. Assert (pStrings != NULL);
  367. m_pStringList = pStrings;
  368. m_pCurrent = m_pStringList->m_pBegin;
  369. m_cRefs = 1;
  370. m_pStringList->AddRef();
  371. }
  372. /*===================================================================
  373. CStrListIterator::CStrListIterator
  374. Destructor
  375. ===================================================================*/
  376. CStrListIterator::~CStrListIterator()
  377. {
  378. m_pStringList->Release();
  379. }
  380. /*===================================================================
  381. CStrListIterator::QueryInterface
  382. CStrListIterator::AddRef
  383. CStrListIterator::Release
  384. IUnknown members for CServVarsIterator object.
  385. ===================================================================*/
  386. STDMETHODIMP CStrListIterator::QueryInterface(REFIID iid, void **ppvObj)
  387. {
  388. if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
  389. {
  390. AddRef();
  391. *ppvObj = this;
  392. return S_OK;
  393. }
  394. *ppvObj = NULL;
  395. return E_NOINTERFACE;
  396. }
  397. STDMETHODIMP_(ULONG) CStrListIterator::AddRef()
  398. {
  399. return ++m_cRefs;
  400. }
  401. STDMETHODIMP_(ULONG) CStrListIterator::Release()
  402. {
  403. if (--m_cRefs > 0)
  404. return m_cRefs;
  405. delete this;
  406. return 0;
  407. }
  408. /*===================================================================
  409. CStrListIterator::Clone
  410. Clone this iterator (standard method)
  411. ===================================================================*/
  412. STDMETHODIMP CStrListIterator::Clone(IEnumVARIANT **ppEnumReturn)
  413. {
  414. CStrListIterator *pNewIterator = new CStrListIterator(m_pStringList);
  415. if (pNewIterator == NULL)
  416. return E_OUTOFMEMORY;
  417. // new iterator should point to same location as this.
  418. pNewIterator->m_pCurrent = m_pCurrent;
  419. *ppEnumReturn = pNewIterator;
  420. return S_OK;
  421. }
  422. /*===================================================================
  423. CStrListIterator::Next
  424. Get next value (standard method)
  425. To rehash standard OLE semantics:
  426. We get the next "cElements" from the collection and store them
  427. in "rgVariant" which holds at least "cElements" items. On
  428. return "*pcElementsFetched" contains the actual number of elements
  429. stored. Returns S_FALSE if less than "cElements" were stored, S_OK
  430. otherwise.
  431. ===================================================================*/
  432. STDMETHODIMP CStrListIterator::Next(unsigned long cElementsRequested, VARIANT *rgVariant, unsigned long *pcElementsFetched)
  433. {
  434. // give a valid pointer value to 'pcElementsFetched'
  435. //
  436. unsigned long cElementsFetched;
  437. if (pcElementsFetched == NULL)
  438. pcElementsFetched = &cElementsFetched;
  439. // Loop through the collection until either we reach the end or
  440. // cElements becomes zero
  441. //
  442. unsigned long cElements = cElementsRequested;
  443. *pcElementsFetched = 0;
  444. while (cElements > 0 && m_pCurrent != NULL)
  445. {
  446. BSTR bstrT = SysAllocString(m_pCurrent->QueryValue());
  447. if (bstrT == NULL)
  448. return E_OUTOFMEMORY;
  449. V_VT(rgVariant) = VT_BSTR;
  450. V_BSTR(rgVariant) = bstrT;
  451. ++rgVariant;
  452. --cElements;
  453. ++*pcElementsFetched;
  454. m_pCurrent = m_pCurrent->QueryNext();
  455. }
  456. // initialize the remaining variants
  457. //
  458. while (cElements-- > 0)
  459. VariantInit(rgVariant++);
  460. return (*pcElementsFetched == cElementsRequested)? S_OK : S_FALSE;
  461. }
  462. /*===================================================================
  463. CStrListIterator::Skip
  464. Skip items (standard method)
  465. To rehash standard OLE semantics:
  466. We skip over the next "cElements" from the collection.
  467. Returns S_FALSE if less than "cElements" were skipped, S_OK
  468. otherwise.
  469. ===================================================================*/
  470. STDMETHODIMP CStrListIterator::Skip(unsigned long cElements)
  471. {
  472. /* Loop through the collection until either we reach the end or
  473. * cElements becomes zero
  474. */
  475. while (cElements > 0 && m_pCurrent != NULL)
  476. {
  477. --cElements;
  478. m_pCurrent = m_pCurrent->QueryNext();
  479. }
  480. return (cElements == 0)? S_OK : S_FALSE;
  481. }
  482. /*===================================================================
  483. CStrListIterator::Reset
  484. Reset the iterator (standard method)
  485. ===================================================================*/
  486. STDMETHODIMP CStrListIterator::Reset()
  487. {
  488. m_pCurrent = m_pStringList->m_pBegin;
  489. return S_OK;
  490. }