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.

623 lines
12 KiB

  1. // Strings.cpp : Implementation of CStrings
  2. #include "stdafx.h"
  3. #include "DevCon2.h"
  4. #include "xStrings.h"
  5. #include "StringsEnum.h"
  6. #include "utils.h"
  7. /////////////////////////////////////////////////////////////////////////////
  8. // CStrings
  9. CStrings::~CStrings()
  10. {
  11. DWORD c;
  12. if(pMultiStrings) {
  13. for(c=0;c<Count;c++) {
  14. SysFreeString(pMultiStrings[c]);
  15. }
  16. delete [] pMultiStrings;
  17. }
  18. }
  19. STDMETHODIMP CStrings::get_Count(long *pVal)
  20. {
  21. *pVal = (long)Count;
  22. return S_OK;
  23. }
  24. STDMETHODIMP CStrings::Item(VARIANT Index, VARIANT *pVal)
  25. {
  26. HRESULT hr;
  27. DWORD i;
  28. BSTR ValueCopy = NULL;
  29. if(!IsNoArg(&Index)) {
  30. //
  31. // get single value
  32. //
  33. hr = GetIndex(&Index,&i);
  34. if(FAILED(hr)) {
  35. return hr;
  36. }
  37. ValueCopy = SysAllocStringLen(pMultiStrings[i],SysStringLen(pMultiStrings[i]));
  38. if(!ValueCopy) {
  39. return E_OUTOFMEMORY;
  40. }
  41. VariantInit(pVal);
  42. V_VT(pVal) = VT_BSTR;
  43. V_BSTR(pVal) = ValueCopy;
  44. return S_OK;
  45. }
  46. //
  47. // return collection as an array of strings
  48. //
  49. #if 1
  50. SAFEARRAY *pArray;
  51. SAFEARRAYBOUND bounds[1];
  52. LONG ind[1];
  53. bounds[0].lLbound = 1;
  54. bounds[0].cElements = Count;
  55. VARIANT v;
  56. pArray = SafeArrayCreate(VT_VARIANT,1,bounds);
  57. if(!pArray) {
  58. return E_OUTOFMEMORY;
  59. }
  60. DWORD c;
  61. VariantInit(&v);
  62. for(c=0;c<Count;c++) {
  63. ind[0] = (LONG)(c+1);
  64. V_VT(&v) = VT_BSTR;
  65. V_BSTR(&v) = pMultiStrings[c];
  66. hr = SafeArrayPutElement(pArray,ind,&v);
  67. if(FAILED(hr)) {
  68. SafeArrayDestroy(pArray);
  69. return hr;
  70. }
  71. }
  72. VariantInit(pVal);
  73. V_VT(pVal) = VT_ARRAY | VT_VARIANT;
  74. V_ARRAY(pVal) = pArray;
  75. #else
  76. SAFEARRAY *pArray;
  77. SAFEARRAYBOUND bounds[1];
  78. LONG ind[1];
  79. bounds[0].lLbound = 1;
  80. bounds[0].cElements = Count;
  81. pArray = SafeArrayCreate(VT_BSTR,1,bounds);
  82. if(!pArray) {
  83. return E_OUTOFMEMORY;
  84. }
  85. DWORD c;
  86. for(c=0;c<Count;c++) {
  87. ind[0] = (LONG)(c+1);
  88. hr = SafeArrayPutElement(pArray,ind,pMultiStrings[c]);
  89. if(FAILED(hr)) {
  90. SafeArrayDestroy(pArray);
  91. return hr;
  92. }
  93. }
  94. VariantInit(pVal);
  95. V_VT(pVal) = VT_ARRAY | VT_BSTR;
  96. V_ARRAY(pVal) = pArray;
  97. #endif
  98. return S_OK;
  99. }
  100. STDMETHODIMP CStrings::get__NewEnum(IUnknown **ppUnk)
  101. {
  102. *ppUnk = NULL;
  103. HRESULT hr;
  104. CComObject<CStringsEnum> *pEnum = NULL;
  105. hr = CComObject<CStringsEnum>::CreateInstance(&pEnum);
  106. if(FAILED(hr)) {
  107. return hr;
  108. }
  109. if(!pEnum) {
  110. return E_OUTOFMEMORY;
  111. }
  112. pEnum->AddRef();
  113. if(!pEnum->CopyStrings(pMultiStrings,Count)) {
  114. pEnum->Release();
  115. return E_OUTOFMEMORY;
  116. }
  117. *ppUnk = pEnum;
  118. return S_OK;
  119. }
  120. HRESULT CStrings::InternalAdd(LPCWSTR Value, UINT len)
  121. {
  122. if(len == (UINT)(-1)) {
  123. len = wcslen(Value);
  124. }
  125. BSTR ValueCopy = NULL;
  126. if(!IncreaseArraySize(1)) {
  127. return E_OUTOFMEMORY;
  128. }
  129. ValueCopy = SysAllocStringLen(Value,len);
  130. if(!ValueCopy) {
  131. return E_OUTOFMEMORY;
  132. }
  133. pMultiStrings[Count++] = ValueCopy;
  134. return S_OK;
  135. }
  136. STDMETHODIMP CStrings::Add(VARIANT Value)
  137. {
  138. return InternalInsert(Count,&Value);
  139. }
  140. BOOL CStrings::IncreaseArraySize(DWORD strings)
  141. {
  142. BSTR* pNewStrings;
  143. DWORD Inc;
  144. DWORD c;
  145. if((ArraySize-Count)>=strings) {
  146. return TRUE;
  147. }
  148. Inc = ArraySize + strings + 32;
  149. pNewStrings = new BSTR[Inc];
  150. if(!pNewStrings) {
  151. return FALSE;
  152. }
  153. for(c=0;c<Count;c++) {
  154. pNewStrings[c] = pMultiStrings[c];
  155. }
  156. delete [] pMultiStrings;
  157. pMultiStrings = pNewStrings;
  158. ArraySize = Inc;
  159. return TRUE;
  160. }
  161. STDMETHODIMP CStrings::Insert(VARIANT Index, VARIANT Value)
  162. {
  163. HRESULT hr;
  164. DWORD i;
  165. hr = GetIndex(&Index,&i);
  166. if(FAILED(hr)) {
  167. return hr;
  168. }
  169. //
  170. // allow i==Count
  171. //
  172. if(i>Count) {
  173. return E_INVALIDARG;
  174. }
  175. return InternalInsert(i,&Value);
  176. }
  177. STDMETHODIMP CStrings::Remove(VARIANT Index)
  178. {
  179. HRESULT hr;
  180. DWORD i;
  181. hr = GetIndex(&Index,&i);
  182. if(FAILED(hr)) {
  183. return hr;
  184. }
  185. if(i>=Count) {
  186. return E_INVALIDARG;
  187. }
  188. DWORD c;
  189. SysFreeString(pMultiStrings[i]);
  190. Count--;
  191. for(c=i;c<Count;c++) {
  192. pMultiStrings[c] = pMultiStrings[c+1];
  193. }
  194. return S_OK;
  195. }
  196. HRESULT CStrings::InternalInsert(DWORD Index, LPVARIANT pVal)
  197. {
  198. CComVariant v;
  199. HRESULT hr;
  200. SAFEARRAY *pArray;
  201. VARTYPE vt;
  202. CComPtr<IEnumVARIANT> pEnum;
  203. if(IsArrayVariant(pVal,&pArray,&vt)) {
  204. return InternalInsertArray(Index,vt,pArray);
  205. }
  206. if(IsCollectionVariant(pVal,&pEnum)) {
  207. return InternalInsertCollection(Index,pEnum);
  208. }
  209. //
  210. // now see if we can treat it as a string
  211. //
  212. hr = v.ChangeType(VT_BSTR,pVal);
  213. if(SUCCEEDED(hr)) {
  214. return InternalInsertString(Index,V_BSTR(&v));
  215. }
  216. return hr;
  217. }
  218. HRESULT CStrings::InternalInsertArray(DWORD Index, VARTYPE vt, SAFEARRAY *pArray)
  219. {
  220. HRESULT hr;
  221. UINT dims = SafeArrayGetDim(pArray);
  222. if(!dims) {
  223. return S_FALSE;
  224. }
  225. long *pDims = new long[dims];
  226. if(!pDims) {
  227. return E_OUTOFMEMORY;
  228. }
  229. //
  230. // write values into a temporary collection
  231. //
  232. CComObject<CStrings> *pStringTemp = NULL;
  233. hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
  234. if(FAILED(hr)) {
  235. delete [] pDims;
  236. return hr;
  237. }
  238. pStringTemp->AddRef();
  239. hr = InternalInsertArrayDim(pStringTemp,vt,pArray,pDims,0,dims);
  240. delete [] pDims;
  241. if(FAILED(hr)) {
  242. pStringTemp->Release();
  243. return hr;
  244. }
  245. //
  246. // now quickly insert pStringTemp strings into this collection
  247. //
  248. DWORD Added = pStringTemp->Count;
  249. if(!IncreaseArraySize(Added)) {
  250. pStringTemp->Release();
  251. return E_OUTOFMEMORY;
  252. }
  253. DWORD c;
  254. for(c=Count;c>Index;c--) {
  255. pMultiStrings[c-1+Added] = pMultiStrings[c-1];
  256. }
  257. for(c=0;c<Added;c++) {
  258. pMultiStrings[Index+c] = pStringTemp->pMultiStrings[c];
  259. }
  260. Count += Added;
  261. //
  262. // throw strings in temp collection away without free'ing them
  263. //
  264. pStringTemp->Count = 0;
  265. pStringTemp->Release();
  266. return S_OK;
  267. }
  268. HRESULT CStrings::InternalInsertArrayDim(CComObject<CStrings> *pStringTemp, VARTYPE vt, SAFEARRAY *pArray,long *pDims,UINT dim,UINT dims)
  269. {
  270. long lower;
  271. long upper;
  272. long aIndex;
  273. HRESULT hr;
  274. UINT nextdim = dim+1;
  275. hr = SafeArrayGetLBound(pArray,nextdim,&lower);
  276. if(FAILED(hr)) {
  277. return hr;
  278. }
  279. hr = SafeArrayGetUBound(pArray,nextdim,&upper);
  280. if(FAILED(hr)) {
  281. return hr;
  282. }
  283. if(nextdim<dims) {
  284. for(aIndex=lower;aIndex<=upper;aIndex++) {
  285. pDims[dim] = aIndex;
  286. hr = InternalInsertArrayDim(pStringTemp,vt,pArray,pDims,nextdim,dims);
  287. if(FAILED(hr)) {
  288. return hr;
  289. }
  290. }
  291. return S_OK;
  292. }
  293. if(upper-lower<0) {
  294. return S_OK;
  295. }
  296. //
  297. // write values for this vector
  298. //
  299. UINT elemsize = SafeArrayGetElemsize(pArray);
  300. PBYTE buffer = new BYTE[elemsize];
  301. if(!buffer) {
  302. return E_OUTOFMEMORY;
  303. }
  304. for(aIndex=lower;aIndex<=upper;aIndex++) {
  305. pDims[dim] = aIndex;
  306. hr = SafeArrayGetElement(pArray,pDims,buffer);
  307. if(FAILED(hr)) {
  308. delete [] buffer;
  309. return hr;
  310. }
  311. VARIANT v;
  312. if(elemsize < sizeof(VARIANT)) {
  313. VariantInit(&v);
  314. V_VT(&v) = vt & ~(VT_ARRAY|VT_VECTOR|VT_BYREF);
  315. memcpy(&V_BYREF(&v),buffer,elemsize);
  316. } else {
  317. memcpy(&v,buffer,sizeof(v));
  318. }
  319. if(V_VT(&v)!=VT_EMPTY) {
  320. //
  321. // only add non-empty items
  322. //
  323. hr = pStringTemp->Add(v);
  324. }
  325. VariantClear(&v);
  326. if(FAILED(hr)) {
  327. delete [] buffer;
  328. return hr;
  329. }
  330. }
  331. return S_OK;
  332. }
  333. HRESULT CStrings::InternalInsertCollection(DWORD Index, IEnumVARIANT *pEnum)
  334. {
  335. pEnum->Reset();
  336. CComVariant ent;
  337. //
  338. // get first item - this allows us to do little work if
  339. // source collection is empty
  340. //
  341. HRESULT hr = pEnum->Next(1,&ent,NULL);
  342. if(FAILED(hr)) {
  343. return hr;
  344. }
  345. if(hr != S_OK) {
  346. //
  347. // empty
  348. //
  349. return S_FALSE;
  350. }
  351. //
  352. // create a temporary collection for working
  353. //
  354. CComObject<CStrings> *pStringTemp = NULL;
  355. hr = CComObject<CStrings>::CreateInstance(&pStringTemp);
  356. if(FAILED(hr)) {
  357. return hr;
  358. }
  359. pStringTemp->AddRef();
  360. do {
  361. //
  362. // this will recursively process an element of this collection
  363. //
  364. hr = pStringTemp->Add(ent);
  365. if(FAILED(hr)) {
  366. break;
  367. }
  368. //
  369. // next
  370. //
  371. ent.Clear();
  372. hr = pEnum->Next(1,&ent,NULL);
  373. } while(hr == S_OK);
  374. if(FAILED(hr)) {
  375. pStringTemp->Release();
  376. return hr;
  377. }
  378. //
  379. // now quickly insert pStringTemp strings into this collection
  380. //
  381. DWORD Added = pStringTemp->Count;
  382. if(!IncreaseArraySize(Added)) {
  383. pStringTemp->Release();
  384. return E_OUTOFMEMORY;
  385. }
  386. DWORD c;
  387. for(c=Count;c>Index;c--) {
  388. pMultiStrings[c-1+Added] = pMultiStrings[c-1];
  389. }
  390. for(c=0;c<Added;c++) {
  391. pMultiStrings[Index+c] = pStringTemp->pMultiStrings[c];
  392. }
  393. Count += Added;
  394. //
  395. // throw strings in temp collection away without free'ing them
  396. //
  397. pStringTemp->Count = 0;
  398. pStringTemp->Release();
  399. return S_OK;
  400. }
  401. HRESULT CStrings::InternalInsertString(DWORD Index, BSTR pString)
  402. {
  403. DWORD c;
  404. BSTR ValueCopy = NULL;
  405. if(Index>Count) {
  406. return E_INVALIDARG;
  407. }
  408. if(!IncreaseArraySize(1)) {
  409. return E_OUTOFMEMORY;
  410. }
  411. ValueCopy = SysAllocStringLen(pString,SysStringLen(pString));
  412. if(!ValueCopy) {
  413. return E_OUTOFMEMORY;
  414. }
  415. for(c=Count;c>Index;c--) {
  416. pMultiStrings[c] = pMultiStrings[c-1];
  417. }
  418. pMultiStrings[Index] = ValueCopy;
  419. Count++;
  420. return S_OK;
  421. }
  422. HRESULT CStrings::GetMultiSz(LPWSTR *pResult, DWORD *pSize)
  423. {
  424. //
  425. // get a multi-sz buffer from this list of strings
  426. //
  427. DWORD c;
  428. DWORD buflen = 1;
  429. DWORD actlen = 0;
  430. LPWSTR buffer = NULL;
  431. for(c=0;c<Count;c++) {
  432. //
  433. // estimate buffer size
  434. //
  435. DWORD ellen = SysStringLen(pMultiStrings[c]);
  436. if(ellen) {
  437. buflen += ellen+1;
  438. }
  439. }
  440. buffer = new WCHAR[buflen];
  441. if(!buffer) {
  442. return E_OUTOFMEMORY;
  443. }
  444. for(c=0;c<Count;c++) {
  445. //
  446. // first NULL of string might be inside string
  447. // in such a case, terminate string there
  448. //
  449. DWORD ellen = wcslen(pMultiStrings[c]);
  450. if(ellen == 0) {
  451. continue;
  452. }
  453. memcpy(buffer+actlen,pMultiStrings[c],ellen*sizeof(WCHAR));
  454. actlen += ellen;
  455. buffer[actlen++] = 0;
  456. }
  457. buffer[actlen++] = 0;
  458. *pResult = buffer;
  459. *pSize = actlen;
  460. return S_OK;
  461. }
  462. HRESULT CStrings::FromMultiSz(LPCWSTR pMultiSz)
  463. {
  464. //
  465. // append to list from multi-sz
  466. // usually used with a temporary/new CStrings
  467. //
  468. DWORD len = 0;
  469. HRESULT hr;
  470. for(;*pMultiSz;pMultiSz+=len+1) {
  471. len = wcslen(pMultiSz);
  472. hr = InternalAdd(pMultiSz,len);
  473. if(FAILED(hr)) {
  474. return hr;
  475. }
  476. }
  477. return S_OK;
  478. }
  479. HRESULT CStrings::GetIndex(VARIANT *Index, DWORD *pAt)
  480. {
  481. CComVariant v;
  482. HRESULT hr;
  483. if(IsNumericVariant(Index)) {
  484. hr = v.ChangeType(VT_I4,Index);
  485. if(FAILED(hr)) {
  486. return DISP_E_TYPEMISMATCH;
  487. }
  488. if(V_I4(&v)<1) {
  489. return E_INVALIDARG;
  490. }
  491. *pAt = ((DWORD)V_I4(&v))-1;
  492. return S_OK;
  493. }
  494. //
  495. // user actually supplied instance id
  496. //
  497. hr = v.ChangeType(VT_BSTR,Index);
  498. if(FAILED(hr)) {
  499. return DISP_E_TYPEMISMATCH;
  500. }
  501. if(!Count) {
  502. //
  503. // cannot match anything
  504. //
  505. return E_INVALIDARG;
  506. }
  507. //
  508. // find an existing device that matches this
  509. //
  510. DWORD c;
  511. for(c=0;c<Count;c++) {
  512. if(wcscmp(pMultiStrings[c],V_BSTR(&v))==0) {
  513. *pAt = c;
  514. return S_OK;
  515. }
  516. }
  517. //
  518. // none found, run through again ignoring case
  519. //
  520. if(!IsCaseSensative) {
  521. for(c=0;c<Count;c++) {
  522. if(_wcsicmp(pMultiStrings[c],V_BSTR(&v))==0) {
  523. *pAt = c;
  524. return S_OK;
  525. }
  526. }
  527. }
  528. //
  529. // still none found
  530. //
  531. return E_INVALIDARG;
  532. }
  533. BOOL CStrings::InternalEnum(DWORD index,BSTR *pNext)
  534. {
  535. //
  536. // note that pNext returned is not a unique string
  537. //
  538. if(index>=Count) {
  539. return FALSE;
  540. }
  541. *pNext = pMultiStrings[index];
  542. return TRUE;
  543. }
  544. STDMETHODIMP CStrings::Find(BSTR name, long *pFound)
  545. {
  546. //
  547. // find an existing device that matches this
  548. //
  549. DWORD c;
  550. for(c=0;c<Count;c++) {
  551. if(wcscmp(pMultiStrings[c],name)==0) {
  552. *pFound = (long)(c+1);
  553. return S_OK;
  554. }
  555. }
  556. //
  557. // none found, run through again ignoring case
  558. //
  559. if(!IsCaseSensative) {
  560. for(c=0;c<Count;c++) {
  561. if(_wcsicmp(pMultiStrings[c],name)==0) {
  562. *pFound = (long)(c+1);
  563. return S_OK;
  564. }
  565. }
  566. }
  567. *pFound = 0;
  568. return S_FALSE;
  569. }
  570. STDMETHODIMP CStrings::get_CaseSensative(VARIANT_BOOL *pVal)
  571. {
  572. *pVal = IsCaseSensative ? VARIANT_TRUE : VARIANT_FALSE;
  573. return S_OK;
  574. }
  575. STDMETHODIMP CStrings::put_CaseSensative(VARIANT_BOOL newVal)
  576. {
  577. IsCaseSensative = newVal ? VARIANT_TRUE : VARIANT_FALSE;
  578. return S_OK;
  579. }