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.

2801 lines
83 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1993
  5. //
  6. // File: propvar.cxx
  7. //
  8. // Contents: PROPVARIANT manipulation code
  9. //
  10. //
  11. //---------------------------------------------------------------------------
  12. #include "pch.cxx"
  13. #ifndef newk
  14. #define newk(Tag, pCounter) new
  15. #endif
  16. extern "C" UNICODECALLOUTS UnicodeCallouts;
  17. // The below variant types are supported in property set streams. In addition,
  18. // the variants found in an array of variants (VT_VECTOR | VT_VARIANT) can only
  19. // contain the types listed below as legal for arrays. Nested vectors of
  20. // VT_VARIANT are specifically *allowed*.
  21. //
  22. // dd xx symbolic name field size
  23. // -- --- ------------- ----- ----
  24. // -1 - ffff VT_ILLEGAL <none> can't legally be stored
  25. //
  26. // 0 - x00 VT_EMPTY <none> 0
  27. // 1 - x01 VT_NULL <none> 0
  28. //
  29. // 16 - x10 VT_I1 CHAR cVal sizeof(char)
  30. // 17 - x11 VT_UI1 UCHAR bVal sizeof(char)
  31. //
  32. // 2 - x02 VT_I2 short iVal sizeof(short)
  33. // 18 - x12 VT_UI2 USHORT uiVal sizeof(short)
  34. // 11 - x0b VT_BOOL VARIANT_BOOL boolVal sizeof(short)
  35. //
  36. // 3 - x03 VT_I4 long lVal sizeof(long)
  37. // 19 - x13 VT_UI4 ULONG ulVal sizeof(long)
  38. // 4 - x04 VT_R4 float fltVal sizeof(long)
  39. // 10 - x0a VT_ERROR SCODE scode sizeof(long)
  40. //
  41. // 20 - x14 VT_I8 LARGE_INTEGER hVal sizeof(ll)
  42. // 21 - x15 VT_UI8 ULARGE_INTEGER uhVal sizeof(ll)
  43. // 5 - x05 VT_R8 double dblVal sizeof(ll)
  44. // 6 - x06 VT_CY CY cyVal sizeof(ll)
  45. // 7 - x07 VT_DATE DATE date sizeof(ll)
  46. // 64 - x40 VT_FILETIME FILETIME filetime sizeof(ll)
  47. //
  48. // 72 - x48 VT_CLSID CLSID *puuid sizeof(GUID)
  49. //
  50. // 65 - x41 VT_BLOB BLOB blob counted array of bytes
  51. // 70 - x46 VT_BLOB_OBJECT BLOB blob counted array of bytes
  52. // 71 - x47 VT_CF CLIPDATA *pclipdata " + ulClipFmt
  53. // 66 - x42 VT_STREAM LPSTR pszVal counted array of bytes
  54. // 68 - x44 VT_STREAMED_OBJECT LPSTR pszVal counted array of bytes
  55. // 67 - x43 VT_STORAGE LPSTR pszVal counted array of bytes
  56. // 69 - x45 VT_STORED_OBJECT LPSTR pszVal counted array of bytes
  57. // 8 - x08 VT_BSTR BSTR bstrVal counted array of bytes
  58. // 30 - x1e VT_LPSTR LPSTR pszVal counted array of bytes
  59. //
  60. // 31 - x1f VT_LPWSTR LPWSTR pwszVal counted array of WCHARs
  61. //
  62. // x1010 VT_VECTOR | VT_I1 CAC cac cElems * sizeof(char)
  63. // x1011 VT_VECTOR | VT_UI1 CAUB caub cElems * sizeof(char)
  64. //
  65. // x1002 VT_VECTOR | VT_I2 CAI cai cElems * sizeof(short)
  66. // x1012 VT_VECTOR | VT_UI2 CAUI caui cElems * sizeof(short)
  67. // x100b VT_VECTOR | VT_BOOL CABOOL cabool cElems * sizeof(short)
  68. //
  69. // x1003 VT_VECTOR | VT_I4 CAL cal cElems * sizeof(long)
  70. // x1013 VT_VECTOR | VT_UI4 CAUL caul cElems * sizeof(long)
  71. // x1004 VT_VECTOR | VT_R4 CAFLT caflt cElems * sizeof(long)
  72. // x100a VT_VECTOR | VT_ERROR CAERROR cascode cElems * sizeof(long)
  73. //
  74. // x1014 VT_VECTOR | VT_I8 CAH cah cElems * sizeof(ll)
  75. // x1015 VT_VECTOR | VT_UI8 CAUH cauh cElems * sizeof(ll)
  76. // x1005 VT_VECTOR | VT_R8 CADBL cadbl cElems * sizeof(ll)
  77. // x1006 VT_VECTOR | VT_CY CACY cacy cElems * sizeof(ll)
  78. // x1007 VT_VECTOR | VT_DATE CADATE cadate cElems * sizeof(ll)
  79. // x1040 VT_VECTOR | VT_FILETIME CAFILETIME cafiletime cElems * sizeof(ll)
  80. //
  81. // x1048 VT_VECTOR | VT_CLSID CACLSID cauuid cElems * sizeof(GUID)
  82. //
  83. // x1047 VT_VECTOR | VT_CF CACLIPDATA caclipdata cElems cntarray of bytes
  84. // x1008 VT_VECTOR | VT_BSTR CABSTR cabstr cElems cntarray of bytes
  85. // x101e VT_VECTOR | VT_LPSTR CALPSTR calpstr cElems cntarray of bytes
  86. //
  87. // x101f VT_VECTOR | VT_LPWSTR CALPWSTR calpwstr cElems cntarray of WCHAR
  88. //
  89. // x100c VT_VECTOR | VT_VARIANT CAPROPVARIANT capropvar cElems variants
  90. // (recurse on each)
  91. //+---------------------------------------------------------------------------
  92. // Function: RtlpConvertToUnicode, private
  93. //
  94. // Synopsis: Convert a MultiByte string to a Unicode string
  95. //
  96. // Arguments: [pch] -- pointer to MultiByte string
  97. // [cb] -- byte length of MultiByte string
  98. // [CodePage] -- property set codepage
  99. // [ppwc] -- pointer to returned pointer to Unicode string
  100. // [pcb] -- returned byte length of Unicode string
  101. // [pstatus] -- pointer to NTSTATUS code
  102. //
  103. // Returns: Nothing
  104. //---------------------------------------------------------------------------
  105. VOID
  106. RtlpConvertToUnicode(
  107. IN CHAR const *pch,
  108. IN ULONG cb,
  109. IN USHORT CodePage,
  110. OUT WCHAR **ppwc,
  111. OUT ULONG *pcb,
  112. OUT NTSTATUS *pstatus)
  113. {
  114. WCHAR *pwszName;
  115. *pstatus = STATUS_SUCCESS;
  116. PROPASSERT(pch != NULL);
  117. PROPASSERT(ppwc != NULL);
  118. PROPASSERT(pcb != NULL);
  119. *ppwc = NULL;
  120. *pcb = 0;
  121. ULONG cwcName;
  122. PROPASSERT(UnicodeCallouts.pfnMultiByteToWideChar != NULL);
  123. pwszName = NULL;
  124. cwcName = 0;
  125. while (TRUE)
  126. {
  127. cwcName = (*UnicodeCallouts.pfnMultiByteToWideChar)(
  128. CodePage,
  129. 0, // dwFlags
  130. pch,
  131. cb,
  132. pwszName,
  133. cwcName);
  134. if (cwcName == 0)
  135. {
  136. delete [] pwszName;
  137. // If there was an error, assume that it was a code-page
  138. // incompatibility problem.
  139. StatusError(pstatus, "RtlpConvertToUnicode: MultiByteToWideChar error",
  140. STATUS_UNMAPPABLE_CHARACTER);
  141. goto Exit;
  142. }
  143. if (pwszName != NULL)
  144. {
  145. DebugTrace(0, DEBTRACE_PROPERTY, (
  146. "RtlpConvertToUnicode: pch='%s'[%x] pwc='%ws'[%x->%x]\n",
  147. pch,
  148. cb,
  149. pwszName,
  150. *pcb,
  151. cwcName * sizeof(WCHAR)));
  152. break;
  153. }
  154. *pcb = cwcName * sizeof(WCHAR);
  155. *ppwc = pwszName = (WCHAR *) newk(mtPropSetStream, NULL) CHAR[*pcb];
  156. if (pwszName == NULL)
  157. {
  158. StatusNoMemory(pstatus, "RtlpConvertToUnicode: no memory");
  159. goto Exit;
  160. }
  161. }
  162. // ----
  163. // Exit
  164. // ----
  165. Exit:
  166. return;
  167. }
  168. //+---------------------------------------------------------------------------
  169. // Function: RtlpConvertToMultiByte, private
  170. //
  171. // Synopsis: Convert a Unicode string to a MultiByte string
  172. //
  173. // Arguments: [pwc] -- pointer to Unicode string
  174. // [cb] -- byte length of Unicode string
  175. // [CodePage] -- property set codepage
  176. // [ppch] -- pointer to returned pointer to MultiByte string
  177. // [pcb] -- returned byte length of MultiByte string
  178. // [pstatus] -- pointer to NTSTATUS code
  179. //
  180. // Returns: Nothing
  181. //---------------------------------------------------------------------------
  182. VOID
  183. RtlpConvertToMultiByte(
  184. IN WCHAR const *pwc,
  185. IN ULONG cb,
  186. IN USHORT CodePage,
  187. OUT CHAR **ppch,
  188. OUT ULONG *pcb,
  189. OUT NTSTATUS *pstatus)
  190. {
  191. ULONG cbName;
  192. CHAR *pszName;
  193. *pstatus = STATUS_SUCCESS;
  194. PROPASSERT(pwc != NULL);
  195. PROPASSERT(ppch != NULL);
  196. PROPASSERT(pcb != NULL);
  197. *ppch = NULL;
  198. *pcb = 0;
  199. PROPASSERT(UnicodeCallouts.pfnWideCharToMultiByte != NULL);
  200. pszName = NULL;
  201. cbName = 0;
  202. while (TRUE)
  203. {
  204. cbName = (*UnicodeCallouts.pfnWideCharToMultiByte)(
  205. CodePage,
  206. 0, // dwFlags
  207. pwc,
  208. cb/sizeof(WCHAR),
  209. pszName,
  210. cbName,
  211. NULL, // lpDefaultChar
  212. NULL); // lpUsedDefaultChar
  213. if (cbName == 0)
  214. {
  215. delete [] pszName;
  216. // If there was an error, assume that it was a code-page
  217. // incompatibility problem.
  218. StatusError(pstatus, "RtlpConvertToMultiByte: WideCharToMultiByte error",
  219. STATUS_UNMAPPABLE_CHARACTER);
  220. goto Exit;
  221. }
  222. if (pszName != NULL)
  223. {
  224. DebugTrace(0, DEBTRACE_PROPERTY, (
  225. "RtlpConvertToMultiByte: pwc='%ws'[%x] pch='%s'[%x->%x]\n",
  226. pwc,
  227. cb,
  228. pszName,
  229. *pcb,
  230. cbName));
  231. break;
  232. }
  233. *pcb = cbName;
  234. *ppch = pszName = newk(mtPropSetStream, NULL) CHAR[cbName];
  235. if (pszName == NULL)
  236. {
  237. StatusNoMemory(pstatus, "RtlpConvertToMultiByte: no memory");
  238. goto Exit;
  239. }
  240. }
  241. // ----
  242. // Exit
  243. // ----
  244. Exit:
  245. return;
  246. }
  247. //+---------------------------------------------------------------------------
  248. // Function: RtlConvertVariantToProperty, private
  249. //
  250. // Synopsis: Convert a PROPVARIANT to a SERIALIZEDPROPERTYVALUE
  251. //
  252. // Arguments: [pvar] -- pointer to PROPVARIANT
  253. // [CodePage] -- property set codepage
  254. // [pprop] -- pointer to SERIALIZEDPROPERTYVALUE
  255. // [pcb] -- pointer to remaining stream length,
  256. // updated to actual property size on return
  257. // [pid] -- propid
  258. // [fVariantVector] -- TRUE if recursing on VT_VECTOR | VT_VARIANT
  259. // [pstatus] -- pointer to NTSTATUS code
  260. //
  261. // Returns: NULL if buffer too small, else input [pprop] argument
  262. //---------------------------------------------------------------------------
  263. // Define a macro which sets a variable named 'cbByteSwap', but
  264. // only on big-endian builds. This value is not needed on little-
  265. // endian builds (because byte-swapping is not necessary).
  266. #ifdef BIGENDIAN
  267. #define CBBYTESWAP(cb) cbByteSwap = cb
  268. #elif LITTLEENDIAN
  269. #define CBBYTESWAP(cb)
  270. #else
  271. #error Either BIGENDIAN or LITTLEENDIAN must be set.
  272. #endif
  273. SERIALIZEDPROPERTYVALUE *
  274. RtlConvertVariantToProperty(
  275. IN PROPVARIANT const *pvar,
  276. IN USHORT CodePage,
  277. OPTIONAL OUT SERIALIZEDPROPERTYVALUE *pprop,
  278. IN OUT ULONG *pcb,
  279. IN PROPID pid,
  280. IN BOOLEAN fVariantVector,
  281. OUT NTSTATUS *pstatus)
  282. {
  283. *pstatus = STATUS_SUCCESS;
  284. // ------
  285. // Locals
  286. // ------
  287. CHAR *pchConvert = NULL;
  288. ULONG count;
  289. BYTE *pbdst;
  290. ULONG cbch = 0;
  291. ULONG cbchdiv = 0;
  292. ULONG cb = 0;
  293. // Size of byte-swapping units (e.g. 2 to swap a WORD).
  294. INT cbByteSwap = 0;
  295. ULONG const *pcount = NULL;
  296. VOID const *pv = NULL;
  297. LONG *pclipfmt = NULL;
  298. BOOLEAN fCheckNullSource = (BOOLEAN) ((pvar->vt & VT_VECTOR) != 0);
  299. BOOLEAN fIllegalType = FALSE;
  300. VOID **ppv;
  301. // -------------------------------------------------------
  302. // Analyze the PropVariant, and store information about it
  303. // in fIllegalType, cb, pv, pcount, count, pclipfmt,
  304. // fCheckNullSource, cbch, chchdiv, and ppv.
  305. // -------------------------------------------------------
  306. switch (pvar->vt)
  307. {
  308. case VT_EMPTY:
  309. case VT_NULL:
  310. fIllegalType = fVariantVector;
  311. break;
  312. #ifdef PROPVAR_VT_I1
  313. case VT_I1:
  314. AssertByteField(cVal); // VT_I1
  315. #endif
  316. case VT_UI1:
  317. AssertByteField(bVal); // VT_UI1
  318. cb = sizeof(pvar->bVal);
  319. pv = &pvar->bVal;
  320. break;
  321. case VT_I2:
  322. case VT_UI2:
  323. case VT_BOOL:
  324. AssertShortField(iVal); // VT_I2
  325. AssertShortField(uiVal); // VT_UI2
  326. AssertShortField(boolVal); // VT_BOOL
  327. cb = sizeof(pvar->iVal);
  328. pv = &pvar->iVal;
  329. // If swapping, swap as a WORD
  330. CBBYTESWAP(cb);
  331. break;
  332. case VT_I4:
  333. case VT_UI4:
  334. case VT_R4:
  335. case VT_ERROR:
  336. AssertLongField(lVal); // VT_I4
  337. AssertLongField(ulVal); // VT_UI4
  338. AssertLongField(fltVal); // VT_R4
  339. AssertLongField(scode); // VT_ERROR
  340. cb = sizeof(pvar->lVal);
  341. pv = &pvar->lVal;
  342. // If swapping, swap as a DWORD
  343. CBBYTESWAP(cb);
  344. break;
  345. case VT_I8:
  346. case VT_UI8:
  347. case VT_FILETIME:
  348. AssertLongLongField(hVal); // VT_I8
  349. AssertLongLongField(uhVal); // VT_UI8
  350. AssertLongLongField(filetime); // VT_FILETIME
  351. cb = sizeof(pvar->hVal);
  352. pv = &pvar->hVal;
  353. // If swapping, swap each DWORD independently.
  354. CBBYTESWAP(sizeof(DWORD));
  355. break;
  356. case VT_R8:
  357. case VT_CY:
  358. case VT_DATE:
  359. AssertLongLongField(dblVal); // VT_R8
  360. AssertLongLongField(cyVal); // VT_CY
  361. AssertLongLongField(date); // VT_DATE
  362. cb = sizeof(pvar->dblVal);
  363. pv = &pvar->dblVal;
  364. // If swapping, swap as a LONGLONG (64 bits).
  365. CBBYTESWAP(cb);
  366. break;
  367. case VT_CLSID:
  368. AssertStringField(puuid); // VT_CLSID
  369. cb = sizeof(GUID);
  370. pv = pvar->puuid;
  371. fCheckNullSource = TRUE;
  372. // If swapping, special handling is required.
  373. CBBYTESWAP( CBBYTESWAP_UID );
  374. break;
  375. case VT_CF:
  376. // Validate the PropVariant
  377. if (pvar->pclipdata == NULL
  378. ||
  379. pvar->pclipdata->cbSize < sizeof(pvar->pclipdata->ulClipFmt) )
  380. {
  381. StatusInvalidParameter(pstatus, "RtlConvertVariantToProperty: pclipdata NULL");
  382. goto Exit;
  383. }
  384. // How many bytes should we copy?
  385. cb = CBPCLIPDATA( *(pvar->pclipdata) );
  386. // Identify the value for this property's count field.
  387. // (which includes sizeof(ulClipFmt))
  388. count = pvar->pclipdata->cbSize;
  389. pcount = &count;
  390. // Identify the clipdata's format & data
  391. pclipfmt = &pvar->pclipdata->ulClipFmt;
  392. pv = pvar->pclipdata->pClipData;
  393. fCheckNullSource = TRUE;
  394. // Note that no byte-swapping of 'pv' is necessary.
  395. break;
  396. case VT_BLOB:
  397. case VT_BLOB_OBJECT:
  398. fIllegalType = fVariantVector;
  399. pcount = &pvar->blob.cbSize;
  400. cb = *pcount;
  401. pv = pvar->blob.pBlobData;
  402. fCheckNullSource = TRUE;
  403. // Note that no byte-swapping of 'pv' is necessary.
  404. break;
  405. case VT_LPSTR:
  406. PROPASSERT(
  407. pvar->pszVal == NULL ||
  408. IsAnsiString(pvar->pszVal, MAXULONG));
  409. // FALLTHROUGH
  410. case VT_BSTR:
  411. count = 0; // allow NULL pointer
  412. pv = pvar->pszVal;
  413. AssertStringField(bstrVal); // VT_BSTR
  414. AssertStringField(pszVal); // VT_LPSTR
  415. // We have the string for an LPSTR, BSTR
  416. // property pointed to by 'pv'. Now we'll perform any
  417. // Ansi/Unicode conversions and byte-swapping that's
  418. // necessary (putting the result in 'pv').
  419. if (pv == NULL)
  420. {
  421. fCheckNullSource = TRUE;
  422. }
  423. else
  424. if (pvar->vt == VT_LPSTR)
  425. {
  426. count = strlen((char *) pv) + 1;
  427. // If the propset is Unicode, convert the LPSTR to Unicode.
  428. if (CodePage == CP_WINUNICODE)
  429. {
  430. // Convert to Unicode.
  431. PROPASSERT(IsAnsiString((CHAR const *) pv, count));
  432. RtlpConvertToUnicode( (CHAR const *) pv,
  433. count, CP_ACP,
  434. // Variants are in the system codepage
  435. (WCHAR **) &pchConvert,
  436. &count,
  437. pstatus);
  438. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  439. // 'pv' always has the ready-to-serialize string.
  440. pv = pchConvert;
  441. // This unicode string may require byte-swapping.
  442. CBBYTESWAP( sizeof(WCHAR) );
  443. }
  444. } // else if (pvar->vt == VT_LPSTR)
  445. else
  446. {
  447. // If this is a BSTR, increment the count to include
  448. // the string terminator.
  449. if (pvar->vt == VT_BSTR)
  450. {
  451. count = BSTRLEN(pv);
  452. // Verify that the input BSTR is terminated.
  453. if (pvar->bstrVal[count/sizeof(OLECHAR)] != ((OLECHAR)'\0'))
  454. {
  455. PROPASSERT(pvar->bstrVal[count/sizeof(OLECHAR)] == OLESTR('\0'));
  456. StatusInvalidParameter(pstatus,
  457. "RtlConvertVariantToProperty: bad BSTR null char");
  458. goto Exit;
  459. }
  460. // Increment the count to include the terminator.
  461. count += sizeof(OLECHAR);
  462. }
  463. else
  464. {
  465. count = (Prop_wcslen((WCHAR *) pv) + 1) * sizeof(WCHAR);
  466. PROPASSERT(IsUnicodeString((WCHAR const *) pv, count));
  467. }
  468. // See if this BSTR requires conversion to the propset's code page
  469. if (CodePage != CP_WINUNICODE // Ansi property set
  470. &&
  471. OLECHAR_IS_UNICODE // BSTRs are Unicode
  472. )
  473. {
  474. // A Unicode to Ansi conversion is required.
  475. PROPASSERT( IsUnicodeString( (WCHAR*)pv, count ));
  476. RtlpConvertToMultiByte(
  477. (WCHAR const *) pv,
  478. count,
  479. CodePage,
  480. &pchConvert,
  481. &count,
  482. pstatus);
  483. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  484. pv = pchConvert;
  485. }
  486. else if (CodePage == CP_WINUNICODE // Unicode property set,
  487. &&
  488. pvar->vt == VT_BSTR // a BSTR property, and
  489. &&
  490. !OLECHAR_IS_UNICODE // BSTRs are Ansi.
  491. )
  492. {
  493. // An Ansi to Unicode conversion is required.
  494. PROPASSERT(IsAnsiString((CHAR const *) pv, count));
  495. PROPASSERT(sizeof(OLECHAR) == sizeof(CHAR));
  496. RtlpConvertToUnicode(
  497. (CHAR const *) pv,
  498. count,
  499. CP_ACP, // In-mem BSTR is in system CP
  500. (WCHAR **) &pchConvert,
  501. &count,
  502. pstatus);
  503. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  504. // 'pv' always holds the ready-to-serialize value.
  505. pv = pchConvert;
  506. // This unicode string may require swapping.
  507. CBBYTESWAP( sizeof(WCHAR) );
  508. }
  509. else
  510. if (CodePage == CP_WINUNICODE)
  511. {
  512. // No conversion is required (i.e., both 'pv' and the
  513. // property set are Unicode). But we must remember
  514. // to perform a byte-swap (if byte-swapping is necessary).
  515. CBBYTESWAP( sizeof(WCHAR) );
  516. }
  517. } // if (pv == NULL) ... else if ... else
  518. // Validate 'pv'.
  519. #ifdef LITTLEENDIAN
  520. PROPASSERT( NULL == pv
  521. ||
  522. CodePage == CP_WINUNICODE && IsUnicodeString((WCHAR*)pv, count)
  523. ||
  524. CodePage != CP_WINUNICODE && IsAnsiString((CHAR*)pv, count) );
  525. #endif
  526. cb = count;
  527. pcount = &count;
  528. break;
  529. case VT_LPWSTR:
  530. AssertStringField(pwszVal); // VT_LPWSTR
  531. PROPASSERT(
  532. pvar->pwszVal == NULL ||
  533. IsUnicodeString(pvar->pwszVal, MAXULONG));
  534. pv = pvar->pwszVal;
  535. if (pv == NULL)
  536. {
  537. count = 0;
  538. fCheckNullSource = TRUE;
  539. }
  540. else
  541. {
  542. // Calculate the [length] field.
  543. count = Prop_wcslen(pvar->pwszVal) + 1;
  544. // If byte-swapping will be necessary to get to the serialized
  545. // format, we'll do so in units of WCHARs.
  546. CBBYTESWAP( sizeof(WCHAR) );
  547. }
  548. cb = count * sizeof(WCHAR);
  549. pcount = &count;
  550. break;
  551. // Vector properties:
  552. #ifdef PROPVAR_VT_I1
  553. case VT_VECTOR | VT_I1:
  554. AssertByteVector(cac); // VT_I1
  555. #endif
  556. case VT_VECTOR | VT_UI1:
  557. AssertByteVector(caub); // VT_UI1
  558. pcount = &pvar->caub.cElems;
  559. cb = *pcount * sizeof(pvar->caub.pElems[0]);
  560. pv = pvar->caub.pElems;
  561. break;
  562. case VT_VECTOR | VT_I2:
  563. case VT_VECTOR | VT_UI2:
  564. case VT_VECTOR | VT_BOOL:
  565. AssertShortVector(cai); // VT_I2
  566. AssertShortVector(caui); // VT_UI2
  567. AssertShortVector(cabool); // VT_BOOL
  568. pcount = &pvar->cai.cElems;
  569. cb = *pcount * sizeof(pvar->cai.pElems[0]);
  570. pv = pvar->cai.pElems;
  571. // If swapping, swap as WORDs
  572. CBBYTESWAP(sizeof(pvar->cai.pElems[0]));
  573. break;
  574. case VT_VECTOR | VT_I4:
  575. case VT_VECTOR | VT_UI4:
  576. case VT_VECTOR | VT_R4:
  577. case VT_VECTOR | VT_ERROR:
  578. AssertLongVector(cal); // VT_I4
  579. AssertLongVector(caul); // VT_UI4
  580. AssertLongVector(caflt); // VT_R4
  581. AssertLongVector(cascode); // VT_ERROR
  582. pcount = &pvar->cal.cElems;
  583. cb = *pcount * sizeof(pvar->cal.pElems[0]);
  584. pv = pvar->cal.pElems;
  585. // If swapping, swap as DWORDs
  586. CBBYTESWAP(sizeof(pvar->cal.pElems[0]));
  587. break;
  588. case VT_VECTOR | VT_I8:
  589. case VT_VECTOR | VT_UI8:
  590. case VT_VECTOR | VT_FILETIME:
  591. AssertLongLongVector(cah); // VT_I8
  592. AssertLongLongVector(cauh); // VT_UI8
  593. AssertLongLongVector(cafiletime);// VT_FILETIME
  594. pcount = &pvar->cah.cElems;
  595. cb = *pcount * sizeof(pvar->cah.pElems[0]);
  596. pv = pvar->cah.pElems;
  597. // If swapping, swap as DWORDs
  598. CBBYTESWAP(sizeof(DWORD));
  599. break;
  600. case VT_VECTOR | VT_R8:
  601. case VT_VECTOR | VT_CY:
  602. case VT_VECTOR | VT_DATE:
  603. AssertLongLongVector(cadbl); // VT_R8
  604. AssertLongLongVector(cacy); // VT_CY
  605. AssertLongLongVector(cadate); // VT_DATE
  606. pcount = &pvar->cah.cElems;
  607. cb = *pcount * sizeof(pvar->cadbl.pElems[0]);
  608. pv = pvar->cadbl.pElems;
  609. // If swapping, swap as LONGLONGs (8 bytes)
  610. CBBYTESWAP(sizeof(pvar->cadbl.pElems[0]));
  611. break;
  612. case VT_VECTOR | VT_CLSID:
  613. AssertVarVector(cauuid, sizeof(GUID));
  614. pcount = &pvar->cauuid.cElems;
  615. cb = *pcount * sizeof(pvar->cauuid.pElems[0]);
  616. pv = pvar->cauuid.pElems;
  617. // If swapping, special handling is required.
  618. CBBYTESWAP( CBBYTESWAP_UID );
  619. break;
  620. case VT_VECTOR | VT_CF:
  621. cbch = sizeof(CLIPDATA);
  622. cbchdiv = sizeof(BYTE);
  623. goto stringvector;
  624. case VT_VECTOR | VT_BSTR:
  625. case VT_VECTOR | VT_LPSTR:
  626. cbchdiv = cbch = sizeof(BYTE);
  627. goto stringvector;
  628. case VT_VECTOR | VT_LPWSTR:
  629. cbchdiv = cbch = sizeof(WCHAR);
  630. goto stringvector;
  631. case VT_VECTOR | VT_VARIANT:
  632. cbch = MAXULONG;
  633. stringvector:
  634. AssertVarVector(caclipdata, sizeof(CLIPDATA)); // VT_CF
  635. AssertStringVector(cabstr); // VT_BSTR
  636. AssertStringVector(calpstr); // VT_LPSTR
  637. AssertStringVector(calpwstr); // VT_LPWSTR
  638. AssertVarVector(capropvar, sizeof(PROPVARIANT));// VT_VARIANT
  639. pcount = &pvar->calpstr.cElems;
  640. ppv = (VOID **) pvar->calpstr.pElems;
  641. break;
  642. default:
  643. DebugTrace(0, DEBTRACE_ERROR, (
  644. "RtlConvertVariantToProperty: unsupported vt=%x\n",
  645. pvar->vt));
  646. StatusInvalidParameter(pstatus, "RtlConvertVariantToProperty: bad type");
  647. goto Exit;
  648. } // switch (pvar->vt)
  649. // At this point we've analyzed the PropVariant, and stored
  650. // information about it in various local variables. Now we
  651. // can use this information to serialize the propvar.
  652. // Early exit if this is an illegal type.
  653. if (fIllegalType)
  654. {
  655. StatusInvalidParameter(pstatus, "RtlConvertVariantToProperty: Illegal VarType");
  656. goto Exit;
  657. }
  658. // Set pbdst to point into the serialization buffer, or to
  659. // NULL if there is no such buffer.
  660. if (pprop == NULL)
  661. {
  662. pbdst = NULL;
  663. }
  664. else
  665. {
  666. pbdst = pprop->rgb;
  667. }
  668. // Is this a Vector of Strings/Variants/CFs?
  669. if (cbch != 0)
  670. {
  671. // Yes.
  672. ULONG cElems;
  673. PROPASSERT(pcount != NULL);
  674. PROPASSERT(*pcount == 0 || ppv != NULL);
  675. PROPASSERT(0 == cbByteSwap);
  676. // Start calculating the serialized size. Include the sizes
  677. // of the VT & element count.
  678. cb = sizeof(ULONG) + sizeof(ULONG);
  679. // Is this a Variant Vector?
  680. if (cbch != MAXULONG)
  681. {
  682. // No. Include each element's length field.
  683. cb += *pcount * sizeof(ULONG);
  684. }
  685. // Is there room in the caller's buffer for everything
  686. // counted so far?
  687. if (*pcb < cb)
  688. {
  689. // No - we won't serialize the data, but we will continue
  690. // to calculate cb.
  691. pprop = NULL;
  692. }
  693. // Write the count of vector elements.
  694. if (pprop != NULL)
  695. {
  696. *(ULONG *) pbdst = PropByteSwap((ULONG) *pcount);
  697. pbdst += sizeof(ULONG);
  698. }
  699. // Walk through the vector and write the elements.
  700. for (cElems = *pcount; cElems > 0; cElems--)
  701. {
  702. ULONG cbcopy = 0;
  703. // Switch on the size of the element.
  704. switch (cbch)
  705. {
  706. //
  707. // VT_VARIANT
  708. //
  709. case MAXULONG:
  710. cbcopy = MAXULONG;
  711. // Perform a recursive serialization
  712. RtlConvertVariantToProperty(
  713. (PROPVARIANT *) ppv,
  714. CodePage,
  715. NULL,
  716. &cbcopy,
  717. PID_ILLEGAL,
  718. TRUE,
  719. pstatus);
  720. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  721. break;
  722. //
  723. // VT_CF
  724. //
  725. case sizeof(CLIPDATA):
  726. // We copy cbSize-sizeof(ulClipFmt) bytes.
  727. if( ((CLIPDATA *) ppv)->cbSize < sizeof(ULONG) )
  728. {
  729. StatusInvalidParameter(pstatus, "RtlConvertVariantToProperty: short cbSize on VT_CF");
  730. goto Exit;
  731. }
  732. else
  733. {
  734. cbcopy = CBPCLIPDATA( *(CLIPDATA*) ppv );
  735. }
  736. // But increment cb to to include sizeof(ulClipFmt)
  737. cb += sizeof(ULONG);
  738. break;
  739. //
  740. // VT_LPWSTR
  741. //
  742. case sizeof(WCHAR):
  743. if (*ppv != NULL)
  744. {
  745. PROPASSERT(IsUnicodeString((WCHAR const *) *ppv, MAXULONG));
  746. cbcopy = (Prop_wcslen((WCHAR *) *ppv) + 1) * sizeof(WCHAR);
  747. pv = *ppv;
  748. // If byte-swapping is necessary, swap in units of WCHARs
  749. CBBYTESWAP( sizeof(WCHAR) );
  750. }
  751. break;
  752. //
  753. // VT_LPSTR/VT_BSTR
  754. //
  755. default:
  756. PROPASSERT(cbch == sizeof(BYTE));
  757. PROPASSERT(pchConvert == NULL);
  758. if (*ppv != NULL)
  759. {
  760. pv = *ppv;
  761. // Is this a BSTR?
  762. if (pvar->vt == (VT_VECTOR | VT_BSTR))
  763. {
  764. // Initialize the # bytes to copy.
  765. cbcopy = BSTRLEN(pv);
  766. // Verify that the BSTR is terminated.
  767. if (((OLECHAR const *) pv)
  768. [cbcopy/sizeof(OLECHAR)] != ( (OLECHAR)'\0'))
  769. {
  770. PROPASSERT(
  771. ((OLECHAR const *) pv)
  772. [cbcopy/sizeof(OLECHAR)] == ((OLECHAR)'\0'));
  773. StatusInvalidParameter(
  774. pstatus,
  775. "RtlConvertVariantToProperty: bad BSTR"
  776. "array null char");
  777. goto Exit;
  778. }
  779. // Also copy the string terminator.
  780. cbcopy += sizeof(OLECHAR);
  781. // If the propset and the BSTR are in mismatched
  782. // codepages (one's Unicode, the other's Ansi),
  783. // correct the BSTR now. In any case, the correct
  784. // string is in 'pv'.
  785. if (CodePage != CP_WINUNICODE // Ansi property set
  786. &&
  787. OLECHAR_IS_UNICODE) // Unicode BSTR
  788. {
  789. PROPASSERT(IsUnicodeString((WCHAR*)pv, cbcopy));
  790. RtlpConvertToMultiByte(
  791. (WCHAR const *) pv,
  792. cbcopy,
  793. CodePage,
  794. &pchConvert,
  795. &cbcopy,
  796. pstatus);
  797. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  798. pv = pchConvert;
  799. }
  800. else
  801. if (CodePage == CP_WINUNICODE // Unicode property set
  802. &&
  803. !OLECHAR_IS_UNICODE) // Ansi BSTRs
  804. {
  805. PROPASSERT(IsAnsiString((CHAR const *) pv, cbcopy));
  806. RtlpConvertToUnicode(
  807. (CHAR const *) pv,
  808. cbcopy,
  809. CP_ACP, // In-mem BSTR is in system CP
  810. (WCHAR **) &pchConvert,
  811. &cbcopy,
  812. pstatus);
  813. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  814. // The Unicode string must have the proper byte order
  815. CBBYTESWAP( sizeof(WCHAR) );
  816. pv = pchConvert;
  817. }
  818. else
  819. if (CodePage == CP_WINUNICODE )
  820. {
  821. // Both the BSTR and the property set are Unicode.
  822. // No conversion is required, but byte-swapping
  823. // is (if byte-swapping is enabled).
  824. CBBYTESWAP( sizeof(WCHAR) );
  825. }
  826. } // if (pvar->vt == (VT_VECTOR | VT_BSTR))
  827. // Otherwise it's an LPSTR
  828. else
  829. {
  830. PROPASSERT(IsAnsiString((char const *) pv, MAXULONG));
  831. PROPASSERT(pvar->vt == (VT_VECTOR | VT_LPSTR));
  832. cbcopy = strlen((char *) pv) + 1; // + trailing null
  833. if (CodePage == CP_WINUNICODE)
  834. {
  835. PROPASSERT(IsAnsiString(
  836. (CHAR const *) pv,
  837. cbcopy));
  838. RtlpConvertToUnicode(
  839. (CHAR const *) pv,
  840. cbcopy,
  841. CP_ACP,
  842. (WCHAR **) &pchConvert,
  843. &cbcopy,
  844. pstatus);
  845. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  846. // If byte-swapping, we'll do so with the WCHARs
  847. CBBYTESWAP( sizeof(WCHAR) );
  848. pv = pchConvert;
  849. }
  850. } // if (pvar->vt == (VT_VECTOR | VT_BSTR)) ... else
  851. } // if (*ppv != NULL)
  852. // In the end, pv should be in the codepage of
  853. // the property set.
  854. #ifdef LITTLEENDIAN
  855. PROPASSERT( NULL == pv
  856. ||
  857. CodePage == CP_WINUNICODE && IsUnicodeString((WCHAR*)pv, cbcopy)
  858. ||
  859. CodePage != CP_WINUNICODE && IsAnsiString((CHAR*)pv, cbcopy));
  860. #endif
  861. break;
  862. } // switch (cbch)
  863. // Add the size of this vector element to the property total
  864. cb += DwordAlign(cbcopy);
  865. // Will there be enough room for this vector element?
  866. if (*pcb < cb)
  867. {
  868. // No - we'll continue (thus calculating the total size
  869. // necessary), but we won't write to the caller's buffer.
  870. pprop = NULL;
  871. }
  872. // Is this a vector of Variants?
  873. if (cbch == MAXULONG)
  874. {
  875. // Yes. Convert this variant.
  876. if (pprop != NULL)
  877. {
  878. RtlConvertVariantToProperty(
  879. (PROPVARIANT *) ppv,
  880. CodePage,
  881. (SERIALIZEDPROPERTYVALUE *) pbdst,
  882. &cbcopy,
  883. PID_ILLEGAL,
  884. TRUE,
  885. pstatus);
  886. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  887. pbdst += cbcopy;
  888. }
  889. ppv = (VOID **) Add2Ptr(ppv, sizeof(PROPVARIANT));
  890. } // if (cbch == MAXULONG)
  891. else
  892. {
  893. // This is a vector of something other than Variants.
  894. PROPASSERT(
  895. cbch == sizeof(BYTE) ||
  896. cbch == sizeof(WCHAR) ||
  897. cbch == sizeof(CLIPDATA));
  898. PROPASSERT(cbchdiv == sizeof(BYTE) || cbchdiv == sizeof(WCHAR));
  899. // Are we writing the serialized property?
  900. if (pprop != NULL)
  901. {
  902. ULONG cbVectElement;
  903. // Calculate the length of the vector element.
  904. cbVectElement = (ULONG) cbcopy/cbchdiv;
  905. // Is this a ClipData?
  906. if (cbch == sizeof(CLIPDATA))
  907. {
  908. // Adjust the length to include sizeof(ulClipFmt)
  909. cbVectElement += sizeof(ULONG);
  910. // Write the vector element length.
  911. *(ULONG *) pbdst = PropByteSwap( cbVectElement );
  912. // Advance pbdst & write the clipboard format.
  913. pbdst += sizeof(ULONG);
  914. *(ULONG *) pbdst = PropByteSwap( ((CLIPDATA *) ppv)->ulClipFmt );
  915. }
  916. else // This isn't a ClipFormat vector element.
  917. {
  918. // Write the vector element length.
  919. *(ULONG *) pbdst = PropByteSwap( cbVectElement );
  920. }
  921. // Advance pbdst & write the property data.
  922. pbdst += sizeof(ULONG);
  923. RtlCopyMemory(
  924. pbdst,
  925. cbch == sizeof(CLIPDATA)?
  926. ((CLIPDATA *) ppv)->pClipData :
  927. pv,
  928. cbcopy);
  929. // Zero out the pad bytes.
  930. RtlZeroMemory(pbdst + cbcopy, DwordRemain(cbcopy));
  931. // If byte-swapping is necessary, do so now.
  932. PBSBuffer( pbdst, DwordAlign(cbcopy), cbByteSwap );
  933. // Advance pbdst to the next property.
  934. pbdst += DwordAlign(cbcopy);
  935. } // if (pprop != NULL)
  936. // Advance ppv to point into the PropVariant at the
  937. // next element in the array.
  938. if (cbch == sizeof(CLIPDATA))
  939. {
  940. ppv = (VOID **) Add2Ptr(ppv, sizeof(CLIPDATA));
  941. }
  942. else
  943. {
  944. ppv++;
  945. delete [] pchConvert;
  946. pchConvert = NULL;
  947. }
  948. } // if (cbch == MAXULONG) ... else
  949. } // for (cElems = *pcount; cElems > 0; cElems--)
  950. } // if (cbch != 0) // STRING/VARIANT/CF VECTOR property
  951. else
  952. {
  953. // This isn't a vector, or if it is, the elements
  954. // aren't Strings, Variants, or CFs.
  955. ULONG cbCopy = cb;
  956. // Adjust cb (the total serialized buffer size) for
  957. // pre-data.
  958. if (pvar->vt != VT_EMPTY)
  959. { // Allow for the VT
  960. cb += sizeof(ULONG);
  961. }
  962. if (pcount != NULL)
  963. { // Allow for the count field
  964. cb += sizeof(ULONG);
  965. }
  966. if (pclipfmt != NULL)
  967. { // Allow for the ulClipFmt field.
  968. cb += sizeof(ULONG);
  969. }
  970. // Is there room in the caller's buffer?
  971. if (*pcb < cb)
  972. { // No - calculate cb but don't write anything.
  973. pprop = NULL;
  974. }
  975. // 'pv' should point to the source data. If it does, then
  976. // we'll copy it into the property set. If it doesn't but
  977. // it should, then we'll report an error.
  978. if (pv != NULL || fCheckNullSource)
  979. {
  980. ULONG cbZero = DwordRemain(cbCopy);
  981. // Do we have a destination (propset) buffer?
  982. if (pprop != NULL)
  983. {
  984. // Does this property have a count field?
  985. if (pcount != NULL)
  986. {
  987. // Write the count & advance pbdst
  988. *(ULONG *) pbdst = PropByteSwap( *pcount );
  989. pbdst += sizeof(ULONG);
  990. }
  991. // Is this a VT_CF?
  992. if (pclipfmt != NULL)
  993. {
  994. // Write the ClipFormat & advance pbdst
  995. *(ULONG *) pbdst = PropByteSwap( (DWORD) *pclipfmt );
  996. pbdst += sizeof(ULONG);
  997. }
  998. }
  999. // Are we missing the source data?
  1000. if (pv == NULL)
  1001. {
  1002. // The Source pointer is NULL. If cbCopy != 0, the passed
  1003. // VARIANT is not properly formed.
  1004. if (cbCopy != 0)
  1005. {
  1006. StatusInvalidParameter(pstatus, "RtlConvertVariantToProperty: bad NULL");
  1007. goto Exit;
  1008. }
  1009. }
  1010. else if (pprop != NULL)
  1011. {
  1012. // We have a non-NULL source & destination.
  1013. // First, copy the bytes from the former to the latter.
  1014. RtlCopyMemory(pbdst, pv, cbCopy);
  1015. // Then, if necessary, swap the bytes in the property
  1016. // set (leaving the PropVariant bytes untouched).
  1017. PBSBuffer( (VOID*) pbdst, cbCopy, cbByteSwap );
  1018. }
  1019. // Did we write the serialization?
  1020. if (pprop != NULL)
  1021. {
  1022. // Zero the padding bytes.
  1023. RtlZeroMemory(pbdst + cbCopy, cbZero);
  1024. // Canonicalize VARIANT_BOOLs. We do this here because
  1025. // we don't want to muck with the caller's buffer directly.
  1026. if ((pvar->vt & ~VT_VECTOR) == VT_BOOL)
  1027. {
  1028. VARIANT_BOOL *pvb = (VARIANT_BOOL *) pbdst;
  1029. VARIANT_BOOL *pvbEnd = &pvb[cbCopy/sizeof(*pvb)];
  1030. while (pvb < pvbEnd)
  1031. {
  1032. if (*pvb
  1033. &&
  1034. PropByteSwap(*pvb) != VARIANT_TRUE)
  1035. {
  1036. DebugTrace(0, DEBTRACE_ERROR, (
  1037. "Patching VARIANT_TRUE value: %hx --> %hx\n",
  1038. *pvb,
  1039. VARIANT_TRUE));
  1040. *pvb = PropByteSwap( (VARIANT_BOOL) VARIANT_TRUE );
  1041. }
  1042. pvb++;
  1043. }
  1044. }
  1045. } // if (pprop != NULL)
  1046. }
  1047. } // if (cbch != 0) ... else // non - STRING/VARIANT/CF VECTOR property
  1048. // Set the VT in the serialized buffer now that all size
  1049. // checks completed.
  1050. if (pprop != NULL && pvar->vt != VT_EMPTY)
  1051. {
  1052. // When byte-swapping the VT, treat it as a DWORD
  1053. // (it's a WORD in the PropVariant, but a DWORD when
  1054. // serialized).
  1055. pprop->dwType = PropByteSwap( (DWORD) pvar->vt );
  1056. }
  1057. // Update the caller's copy of the total size.
  1058. *pcb = DwordAlign(cb);
  1059. Exit:
  1060. delete [] pchConvert;
  1061. return(pprop);
  1062. }
  1063. //+---------------------------------------------------------------------------
  1064. // Function: RtlConvertPropertyToVariant, private
  1065. //
  1066. // Synopsis: Convert a SERIALIZEDPROPERTYVALUE to a PROPVARIANT
  1067. //
  1068. // Arguments: [pprop] -- pointer to SERIALIZEDPROPERTYVALUE
  1069. // [PointerDelta] -- adjustment to pointers to get user addresses
  1070. // [fConvertNullStrings] -- map NULL strings to empty strings
  1071. // [CodePage] -- property set codepage
  1072. // [pvar] -- pointer to PROPVARIANT
  1073. // [pma] -- caller's memory allocation routine
  1074. // [pstatus] -- pointer to NTSTATUS code
  1075. //
  1076. //---------------------------------------------------------------------------
  1077. #define ADJUSTPOINTER(ptr, delta, type)
  1078. VOID
  1079. RtlConvertPropertyToVariant( IN SERIALIZEDPROPERTYVALUE const *pprop,
  1080. IN USHORT CodePage,
  1081. OUT PROPVARIANT *pvar,
  1082. IN PMemoryAllocator *pma,
  1083. OUT NTSTATUS *pstatus)
  1084. {
  1085. *pstatus = STATUS_SUCCESS;
  1086. // ------
  1087. // Locals
  1088. // ------
  1089. // Buffers which must be freed before exiting.
  1090. CHAR *pchConvert = NULL, *pchByteSwap = NULL;
  1091. VOID **ppv = NULL;
  1092. VOID *pv = NULL;
  1093. ULONG cbskip = sizeof(ULONG);
  1094. ULONG cb = 0;
  1095. // Size of byte-swapping units (must be signed).
  1096. INT cbByteSwap = 0;
  1097. BOOLEAN fPostAllocInit = FALSE;
  1098. BOOLEAN fNullLegal = (BOOLEAN) ( (PropByteSwap(pprop->dwType) & VT_VECTOR) != 0 );
  1099. const BOOLEAN fConvertToEmpty = FALSE;
  1100. // ---------------------------------------------------------
  1101. // Based on the VT, calculate cch, ppv, pv, cbskip,
  1102. // cb, fPostAllocInit, fNullLegal, & fConvertToEmpty
  1103. // ---------------------------------------------------------
  1104. // Set the VT in the PropVariant. Note that in 'pprop' it's a
  1105. // DWORD, but it's a WORD in 'pvar'.
  1106. pvar->vt = (VARTYPE) PropByteSwap(pprop->dwType);
  1107. switch (pvar->vt)
  1108. {
  1109. case VT_EMPTY:
  1110. case VT_NULL:
  1111. break;
  1112. #ifdef PROPVAR_VT_I1
  1113. case VT_I1:
  1114. AssertByteField(cVal); // VT_I1
  1115. #endif
  1116. case VT_UI1:
  1117. AssertByteField(bVal); // VT_UI1
  1118. cb = sizeof(pvar->bVal);
  1119. pv = &pvar->bVal;
  1120. break;
  1121. case VT_I2:
  1122. case VT_UI2:
  1123. case VT_BOOL:
  1124. AssertShortField(iVal); // VT_I2
  1125. AssertShortField(uiVal); // VT_UI2
  1126. AssertShortField(boolVal); // VT_BOOL
  1127. cb = sizeof(pvar->iVal);
  1128. pv = &pvar->iVal;
  1129. // If swapping, swap as a WORD
  1130. CBBYTESWAP(cb);
  1131. break;
  1132. case VT_I4:
  1133. case VT_UI4:
  1134. case VT_R4:
  1135. case VT_ERROR:
  1136. AssertLongField(lVal); // VT_I4
  1137. AssertLongField(ulVal); // VT_UI4
  1138. AssertLongField(fltVal); // VT_R4
  1139. AssertLongField(scode); // VT_ERROR
  1140. cb = sizeof(pvar->lVal);
  1141. pv = &pvar->lVal;
  1142. // If swapping, swap as a DWORD
  1143. CBBYTESWAP(cb);
  1144. break;
  1145. case VT_I8:
  1146. case VT_UI8:
  1147. case VT_FILETIME:
  1148. AssertLongLongField(hVal); // VT_I8
  1149. AssertLongLongField(uhVal); // VT_UI8
  1150. AssertLongLongField(filetime); // VT_FILETIME
  1151. cb = sizeof(pvar->hVal);
  1152. pv = &pvar->hVal;
  1153. // If swapping, swap as a pair of DWORDs
  1154. CBBYTESWAP(sizeof(DWORD));
  1155. break;
  1156. case VT_R8:
  1157. case VT_CY:
  1158. case VT_DATE:
  1159. AssertLongLongField(dblVal); // VT_R8
  1160. AssertLongLongField(cyVal); // VT_CY
  1161. AssertLongLongField(date); // VT_DATE
  1162. cb = sizeof(pvar->dblVal);
  1163. pv = &pvar->dblVal;
  1164. // If swapping, swap as a LONGLONG
  1165. CBBYTESWAP(cb);
  1166. break;
  1167. case VT_CLSID:
  1168. AssertStringField(puuid); // VT_CLSID
  1169. cb = sizeof(GUID);
  1170. ppv = (VOID **) &pvar->puuid;
  1171. cbskip = 0;
  1172. // If swapping, special handling is required
  1173. CBBYTESWAP( CBBYTESWAP_UID );
  1174. break;
  1175. case VT_CF:
  1176. // Allocate a CLIPDATA buffer
  1177. pvar->pclipdata = (CLIPDATA *) pma->Allocate(sizeof(CLIPDATA));
  1178. if (pvar->pclipdata == NULL)
  1179. {
  1180. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory for CF");
  1181. goto Exit;
  1182. }
  1183. RtlZeroMemory( pvar->pclipdata, sizeof(CLIPDATA) );
  1184. // Set the size (includes sizeof(ulClipFmt))
  1185. pvar->pclipdata->cbSize = PropByteSwap( ((CLIPDATA *) pprop->rgb)->cbSize );
  1186. if( pvar->pclipdata->cbSize < sizeof(pvar->pclipdata->ulClipFmt) )
  1187. {
  1188. StatusError(pstatus, "RtlConvertPropertyToVariant: Invalid VT_CF cbSize",
  1189. STATUS_INTERNAL_DB_CORRUPTION);
  1190. goto Exit;
  1191. }
  1192. // Set the # bytes-to-copy. We can't use the CBPCLIPDATA macro
  1193. // here because it assumes that the CLIPDATA parameter is correctly
  1194. // byte-swapped.
  1195. cb = PropByteSwap( *(DWORD*) pprop->rgb ) - sizeof(pvar->pclipdata->ulClipFmt);
  1196. // Set the ClipFormat itself.
  1197. pvar->pclipdata->ulClipFmt = PropByteSwap( ((CLIPDATA *) pprop->rgb)->ulClipFmt );
  1198. // Prepare for the alloc & copy. Put the buffer pointer
  1199. // in pClipData, & skip the ulClipFmt in the copy.
  1200. ppv = (VOID **) &pvar->pclipdata->pClipData;
  1201. cbskip += sizeof(ULONG);
  1202. // It's legal for cb to be 0.
  1203. fNullLegal = TRUE;
  1204. // Adjust to the user-mode pointer (Kernel only)
  1205. ADJUSTPOINTER(pvar->pclipdata, PointerDelta, CLIPDATA *);
  1206. break;
  1207. case VT_BLOB:
  1208. case VT_BLOB_OBJECT:
  1209. cb = pvar->blob.cbSize = PropByteSwap( *(ULONG *) pprop->rgb );
  1210. ppv = (VOID **) &pvar->blob.pBlobData;
  1211. fNullLegal = TRUE;
  1212. break;
  1213. case VT_BSTR:
  1214. case VT_LPSTR:
  1215. AssertStringField(bstrVal); // VT_BSTR
  1216. AssertStringField(pszVal); // VT_LPSTR
  1217. // [length field] bytes should be allocated
  1218. cb = PropByteSwap( *(ULONG *) pprop->rgb );
  1219. // When a buffer is allocated, it's pointer will go
  1220. // in *ppv.
  1221. ppv = (VOID **) &pvar->pszVal;
  1222. // Is this a non-empty string?
  1223. if (cb != 0)
  1224. {
  1225. // Is the serialized value one that should be
  1226. // an Ansi string in the PropVariant?
  1227. if (pvar->vt == VT_LPSTR // It's an LPSTR (always Ansi), or
  1228. ||
  1229. pvar->vt == VT_BSTR // It's a BSTR and
  1230. &&
  1231. !OLECHAR_IS_UNICODE ) // BSTRs are Ansi.
  1232. {
  1233. // If the propset is Unicode, we must do a
  1234. // conversion to Ansi.
  1235. if (CodePage == CP_WINUNICODE)
  1236. {
  1237. WCHAR *pwsz = (WCHAR *) Add2ConstPtr(pprop->rgb, sizeof(ULONG));
  1238. // If necessary, swap the WCHARs. 'pwsz' will point to
  1239. // the correct (system-endian) string either way. If an
  1240. // alloc is necessary, 'pchByteSwap' will point to the new
  1241. // buffer.
  1242. PBSInPlaceAlloc( &pwsz, (WCHAR**) &pchByteSwap, pstatus );
  1243. if( !NT_SUCCESS( *pstatus )) goto Exit;
  1244. PROPASSERT(IsUnicodeString( pwsz, cb));
  1245. // Convert the properly-byte-ordered string in 'pwsz'
  1246. // into MBCS, putting the result in pchConvert.
  1247. RtlpConvertToMultiByte(
  1248. pwsz,
  1249. cb,
  1250. CP_ACP, // Use the system default codepage
  1251. &pchConvert,
  1252. &cb,
  1253. pstatus);
  1254. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1255. }
  1256. } // if (pvar->vt == VT_LPSTR) ...
  1257. // Otherwise, even though this string may be
  1258. // Ansi in the Property Set, it must be Unicode
  1259. // in the PropVariant.
  1260. else
  1261. {
  1262. // If necessary, convert to Unicode
  1263. if (CodePage != CP_WINUNICODE)
  1264. {
  1265. PROPASSERT(
  1266. IsAnsiString(
  1267. (CHAR const *)
  1268. Add2ConstPtr(pprop->rgb, sizeof(ULONG)),
  1269. cb));
  1270. RtlpConvertToUnicode(
  1271. (CHAR const *)
  1272. Add2ConstPtr(pprop->rgb, sizeof(ULONG)),
  1273. cb,
  1274. CodePage,
  1275. (WCHAR **) &pchConvert,
  1276. &cb,
  1277. pstatus);
  1278. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1279. } // if (CodePage != CP_WINUNICODE)
  1280. else
  1281. {
  1282. // The value is Unicode both the property set
  1283. // and the PropVariant. If byte-swapping is
  1284. // necessary, we'll do so in units of WCHARs.
  1285. CBBYTESWAP( sizeof(WCHAR) );
  1286. }
  1287. } // if (pvar->vt == VT_LPSTR) ... else
  1288. // If this is a BSTR property, verify that it is terminated
  1289. // appropriately.
  1290. if (VT_BSTR == pvar->vt)
  1291. {
  1292. BSTR bstr = ( NULL == pchConvert )
  1293. ? (BSTR) Add2ConstPtr(pprop->rgb, sizeof(ULONG))
  1294. : (BSTR) pchConvert;
  1295. // On little-endian machines, validate the string.
  1296. #ifdef LITTLEENDIAN
  1297. PROPASSERT( IsOLECHARString( bstr, MAXULONG ));
  1298. #endif
  1299. // Validate the bstr. Note that even though this bstr may
  1300. // be byte-swapped, this 'if' block still works because
  1301. // ByteSwap('\0') == ('\0').
  1302. if( (cb & (sizeof(OLECHAR) - 1)) != 0
  1303. &&
  1304. OLECHAR_IS_UNICODE
  1305. ||
  1306. bstr[cb/sizeof(OLECHAR) - 1] != ((OLECHAR)'\0') )
  1307. {
  1308. StatusError(pstatus, "RtlConvertPropertyToVariant: Invalid BSTR Property",
  1309. STATUS_INTERNAL_DB_CORRUPTION);
  1310. goto Exit;
  1311. }
  1312. } // if (VT_BSTR == pvar->vt)
  1313. } // if (cb != 0)
  1314. fNullLegal = TRUE;
  1315. break;
  1316. case VT_LPWSTR:
  1317. fNullLegal = TRUE;
  1318. AssertStringField(pwszVal); // VT_LPWSTR
  1319. cb = PropByteSwap( *(ULONG *) pprop->rgb ) * sizeof(WCHAR);
  1320. ppv = (VOID **) &pvar->pwszVal;
  1321. // If byte-swapping will be necessary, do so for the WCHARs
  1322. CBBYTESWAP( sizeof(WCHAR) );
  1323. break;
  1324. #ifdef PROPVAR_VT_I1
  1325. case VT_VECTOR | VT_I1:
  1326. AssertByteVector(cac); // VT_I1
  1327. #endif
  1328. case VT_VECTOR | VT_UI1:
  1329. AssertByteVector(caub); // VT_UI1
  1330. pvar->caub.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1331. cb = pvar->caub.cElems * sizeof(pvar->caub.pElems[0]);
  1332. ppv = (VOID **) &pvar->caub.pElems;
  1333. break;
  1334. case VT_VECTOR | VT_I2:
  1335. case VT_VECTOR | VT_UI2:
  1336. case VT_VECTOR | VT_BOOL:
  1337. AssertShortVector(cai); // VT_I2
  1338. AssertShortVector(caui); // VT_UI2
  1339. AssertShortVector(cabool); // VT_BOOL
  1340. pvar->cai.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1341. cb = pvar->cai.cElems * sizeof(pvar->cai.pElems[0]);
  1342. ppv = (VOID **) &pvar->cai.pElems;
  1343. // If swapping, swap as a WORD
  1344. CBBYTESWAP(sizeof(pvar->cai.pElems[0]));
  1345. break;
  1346. case VT_VECTOR | VT_I4:
  1347. case VT_VECTOR | VT_UI4:
  1348. case VT_VECTOR | VT_R4:
  1349. case VT_VECTOR | VT_ERROR:
  1350. AssertLongVector(cal); // VT_I4
  1351. AssertLongVector(caul); // VT_UI4
  1352. AssertLongVector(caflt); // VT_R4
  1353. AssertLongVector(cascode); // VT_ERROR
  1354. pvar->cal.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1355. cb = pvar->cal.cElems * sizeof(pvar->cal.pElems[0]);
  1356. ppv = (VOID **) &pvar->cal.pElems;
  1357. // If byte swapping, swap as DWORDs
  1358. CBBYTESWAP(sizeof(pvar->cal.pElems[0]));
  1359. break;
  1360. case VT_VECTOR | VT_I8:
  1361. case VT_VECTOR | VT_UI8:
  1362. case VT_VECTOR | VT_FILETIME:
  1363. AssertLongLongVector(cah); // VT_I8
  1364. AssertLongLongVector(cauh); // VT_UI8
  1365. AssertLongLongVector(cafiletime); // VT_FILETIME
  1366. pvar->cah.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1367. cb = pvar->cah.cElems * sizeof(pvar->cah.pElems[0]);
  1368. ppv = (VOID **) &pvar->cah.pElems;
  1369. // If byte swapping, swap as DWORDs
  1370. CBBYTESWAP(sizeof(DWORD));
  1371. break;
  1372. case VT_VECTOR | VT_R8:
  1373. case VT_VECTOR | VT_CY:
  1374. case VT_VECTOR | VT_DATE:
  1375. AssertLongLongVector(cadbl); // VT_R8
  1376. AssertLongLongVector(cacy); // VT_CY
  1377. AssertLongLongVector(cadate); // VT_DATE
  1378. pvar->cadbl.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1379. cb = pvar->cadbl.cElems * sizeof(pvar->cadbl.pElems[0]);
  1380. ppv = (VOID **) &pvar->cadbl.pElems;
  1381. // If byte swapping, swap as LONGLONGs
  1382. CBBYTESWAP(sizeof(pvar->cah.pElems[0]));
  1383. break;
  1384. case VT_VECTOR | VT_CLSID:
  1385. AssertVarVector(cauuid, sizeof(GUID));
  1386. pvar->cauuid.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1387. cb = pvar->cauuid.cElems * sizeof(pvar->cauuid.pElems[0]);
  1388. ppv = (VOID **) &pvar->cauuid.pElems;
  1389. // If byte swapping, special handling is required.
  1390. CBBYTESWAP( CBBYTESWAP_UID );
  1391. break;
  1392. case VT_VECTOR | VT_CF:
  1393. // Set the count of clipdatas
  1394. pvar->caclipdata.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1395. // How much should we allocate for caclipdata.pElems, & where
  1396. // should that buffer pointer go?
  1397. cb = pvar->caclipdata.cElems * sizeof(pvar->caclipdata.pElems[0]);
  1398. ppv = (VOID **) &pvar->caclipdata.pElems;
  1399. // We need to do work after pElems is allocated.
  1400. fPostAllocInit = TRUE;
  1401. break;
  1402. case VT_VECTOR | VT_BSTR:
  1403. case VT_VECTOR | VT_LPSTR:
  1404. AssertStringVector(cabstr); // VT_BSTR
  1405. AssertStringVector(calpstr); // VT_LPSTR
  1406. // Put the element count in the PropVar
  1407. pvar->calpstr.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1408. // An array of cElems pointers should be alloced
  1409. cb = pvar->calpstr.cElems * sizeof(CHAR*);
  1410. // Show where the array of pointers should go.
  1411. ppv = (VOID **) &pvar->calpstr.pElems;
  1412. // Additional allocs will be necessary after the vector
  1413. // is alloced.
  1414. fPostAllocInit = TRUE;
  1415. break;
  1416. case VT_VECTOR | VT_LPWSTR:
  1417. AssertStringVector(calpwstr); // VT_LPWSTR
  1418. pvar->calpwstr.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1419. cb = pvar->calpwstr.cElems * sizeof(ULONG);
  1420. ppv = (VOID **) &pvar->calpwstr.pElems;
  1421. fPostAllocInit = TRUE;
  1422. break;
  1423. case VT_VECTOR | VT_VARIANT:
  1424. AssertVariantVector(capropvar); // VT_VARIANT
  1425. pvar->capropvar.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1426. cb = pvar->capropvar.cElems * sizeof(PROPVARIANT);
  1427. ppv = (VOID **) &pvar->capropvar.pElems;
  1428. fPostAllocInit = TRUE;
  1429. break;
  1430. default:
  1431. DebugTrace(0, DEBTRACE_ERROR, (
  1432. "RtlConvertPropertyToVariant: unsupported vt=%x\n",
  1433. pvar->vt));
  1434. StatusInvalidParameter(pstatus, "RtlConvertPropertyToVariant: bad type");
  1435. goto Exit;
  1436. } // switch (pvar->vt)
  1437. // ------------------------------------------------------
  1438. // We've now analyzed the serialized property and learned
  1439. // about it, now we can put it into the PropVariant.
  1440. // ------------------------------------------------------
  1441. // Is this a simple, unaligned scalar?
  1442. if (pv != NULL)
  1443. {
  1444. // Yes. All we need to do is copy some bytes.
  1445. PROPASSERT(pchConvert == NULL);
  1446. RtlCopyMemory(pv, pprop->rgb, cb);
  1447. // We also might need to byte-swap them (but only in the PropVar).
  1448. PBSBuffer( pv, cb, cbByteSwap );
  1449. }
  1450. // Otherwise, we need to allocate memory, to which the
  1451. // PropVariant will point.
  1452. else if (ppv != NULL)
  1453. {
  1454. *ppv = NULL;
  1455. if (!fConvertToEmpty && cb == 0) // Kernel only
  1456. {
  1457. if (!fNullLegal)
  1458. {
  1459. StatusInvalidParameter(pstatus, "RtlConvertPropertyToVariant: bad NULL");
  1460. goto Exit;
  1461. }
  1462. }
  1463. else
  1464. {
  1465. PROPASSERT(cb != 0 || fConvertToEmpty);
  1466. // Allocate the necessary buffer (which we figured out in the
  1467. // switch above). For vector properties,
  1468. // this will just be the pElems buffer at this point.
  1469. // For singleton BSTR properties, we'll skip this allocate
  1470. // altogether; they're allocated with SysStringAlloc.
  1471. if( VT_BSTR != pvar->vt )
  1472. {
  1473. *ppv = pma->Allocate(max(1, cb));
  1474. if (*ppv == NULL)
  1475. {
  1476. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory");
  1477. goto Exit;
  1478. }
  1479. }
  1480. // Can we load the PropVariant with a simple copy?
  1481. if (!fPostAllocInit)
  1482. {
  1483. // Yes - all we need is a copy (and an implicit
  1484. // alloc for BSTRs).
  1485. if (VT_BSTR == pvar->vt)
  1486. {
  1487. // We do the copy with the OleAutomation routine
  1488. // (which does an allocation too).
  1489. // If byte-swapping is necessary, the switch block
  1490. // already took care of it, leaving the buffer in
  1491. // 'pchConvert'.
  1492. PROPASSERT( NULL == *ppv );
  1493. *ppv = (*UnicodeCallouts.pfnSysAllocString)(
  1494. ( pchConvert != NULL )
  1495. ? (OLECHAR *) pchConvert
  1496. : (OLECHAR *) (pprop->rgb + cbskip) );
  1497. if (*ppv == NULL)
  1498. {
  1499. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory");
  1500. goto Exit;
  1501. }
  1502. }
  1503. else
  1504. {
  1505. // Copy the property into the PropVariant.
  1506. RtlCopyMemory(
  1507. *ppv,
  1508. pchConvert != NULL?
  1509. (BYTE const *) pchConvert : pprop->rgb + cbskip,
  1510. cb);
  1511. }
  1512. // If necessary, byte-swap the property (only in the PropVar).
  1513. PBSBuffer( *ppv, cb, cbByteSwap );
  1514. } // if (!fPostAllocInit)
  1515. else
  1516. {
  1517. // We must do more than just a copy.
  1518. // (Thus this is a vector of strings, variants, or CFs).
  1519. ULONG cElems = pvar->calpstr.cElems;
  1520. // Initialize the source pointer to point just beyond
  1521. // the element count.
  1522. BYTE const *pbsrc = pprop->rgb + sizeof(ULONG);
  1523. // Zero all pointers in the pElems array for easy caller cleanup
  1524. ppv = (VOID **) *ppv;
  1525. RtlZeroMemory(ppv, cb);
  1526. // Handle Variants, ClipFormats, & Strings separately.
  1527. if (pvar->vt == (VT_VECTOR | VT_VARIANT))
  1528. {
  1529. PROPVARIANT *pvarT = (PROPVARIANT *) ppv;
  1530. while (cElems-- > 0)
  1531. {
  1532. ULONG cbelement;
  1533. RtlConvertPropertyToVariant(
  1534. (SERIALIZEDPROPERTYVALUE const *) pbsrc,
  1535. CodePage,
  1536. pvarT,
  1537. pma,
  1538. pstatus);
  1539. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1540. cbelement = PropertyLength(
  1541. (SERIALIZEDPROPERTYVALUE const *) pbsrc,
  1542. MAXULONG,
  1543. CPSS_VARIANTVECTOR,
  1544. pstatus);
  1545. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1546. pbsrc += cbelement;
  1547. pvarT++;
  1548. }
  1549. } // if (pvar->vt == (VT_VECTOR | VT_VARIANT))
  1550. else if (pvar->vt == (VT_VECTOR | VT_CF))
  1551. {
  1552. // Set pcd to &pElems[0]
  1553. CLIPDATA *pcd = (CLIPDATA *) ppv;
  1554. // Loop through pElems
  1555. while (cElems-- > 0)
  1556. {
  1557. // What is the size of the clipdata (including sizeof(ulClipFmt))?
  1558. pcd->cbSize = PropByteSwap( ((CLIPDATA *) pbsrc)->cbSize );
  1559. if( pcd->cbSize < sizeof(pcd->ulClipFmt) )
  1560. {
  1561. StatusError(pstatus, "RtlConvertPropertyToVariant: Invalid VT_CF cbSize",
  1562. STATUS_INTERNAL_DB_CORRUPTION);
  1563. goto Exit;
  1564. }
  1565. // How many bytes should we copy to pClipData?
  1566. cb = CBPCLIPDATA( *pcd );
  1567. // Set the ClipFormat & advance pbsrc to the clipdata.
  1568. pcd->ulClipFmt = PropByteSwap( ((CLIPDATA *) pbsrc)->ulClipFmt );
  1569. pbsrc += 2 * sizeof(ULONG);
  1570. // Copy the ClipData into the PropVariant
  1571. pcd->pClipData = NULL;
  1572. if (cb > 0)
  1573. {
  1574. // Get a buffer for the clip data.
  1575. pcd->pClipData = (BYTE *) pma->Allocate(cb);
  1576. if (pcd->pClipData == NULL)
  1577. {
  1578. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory for CF[]");
  1579. goto Exit;
  1580. }
  1581. // Copy the clipdata into pElems[i].pClipData
  1582. RtlCopyMemory(pcd->pClipData, pbsrc, cb);
  1583. ADJUSTPOINTER(pcd->pClipData, PointerDelta, BYTE *);
  1584. } // if (cb > 0)
  1585. // Move pcd to &pElems[i+1], and advance the buffer pointer.
  1586. pcd++;
  1587. pbsrc += DwordAlign(cb);
  1588. } // while (cElems-- > 0)
  1589. } // else if (pvar->vt == (VT_VECTOR | VT_CF))
  1590. else // This is a vector of some kind of string.
  1591. {
  1592. // Assume that characters are CHARs
  1593. ULONG cbch = sizeof(char);
  1594. if (pvar->vt == (VT_VECTOR | VT_LPWSTR))
  1595. {
  1596. // Characters are WCHARs
  1597. cbch = sizeof(WCHAR);
  1598. // If byte-swapping is enabled, LPWSTRs must have
  1599. // their WCHARs swapped.
  1600. CBBYTESWAP( sizeof(WCHAR) );
  1601. }
  1602. while (cElems-- > 0)
  1603. {
  1604. ULONG cbcopy;
  1605. cbcopy = cb = PropByteSwap( *((ULONG *) pbsrc) ) * cbch;
  1606. pbsrc += sizeof(ULONG);
  1607. pv = (VOID *) pbsrc;
  1608. PROPASSERT(*ppv == NULL);
  1609. PROPASSERT(pchConvert == NULL);
  1610. if (fConvertToEmpty || cb != 0)
  1611. {
  1612. // Do we have actual data to work with?
  1613. if (cb != 0)
  1614. {
  1615. // Special BSTR pre-processing ...
  1616. if (pvar->vt == (VT_VECTOR | VT_BSTR))
  1617. {
  1618. // If the propset & in-memory BSTRs are of
  1619. // different Unicode-ness, convert now.
  1620. if (CodePage != CP_WINUNICODE // Ansi PropSet
  1621. &&
  1622. OLECHAR_IS_UNICODE ) // Unicode BSTRs
  1623. {
  1624. PROPASSERT(IsAnsiString((CHAR*) pv, cb));
  1625. RtlpConvertToUnicode(
  1626. (CHAR const *) pv,
  1627. cb,
  1628. CodePage,
  1629. (WCHAR **) &pchConvert,
  1630. &cbcopy,
  1631. pstatus);
  1632. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1633. pv = pchConvert;
  1634. }
  1635. else
  1636. if (CodePage == CP_WINUNICODE // Unicode PropSet
  1637. &&
  1638. !OLECHAR_IS_UNICODE ) // Ansi BSTRs
  1639. {
  1640. // If byte-swapping is necessary, the string from
  1641. // the propset must be swapped before it can be
  1642. // converted to MBCS. If such a conversion
  1643. // is necessary, a new buffer is alloced and
  1644. // put in pchByteSwap. Either way, 'pv' points
  1645. // to the correct string.
  1646. PBSInPlaceAlloc( (WCHAR**) &pv,
  1647. (WCHAR**) &pchByteSwap,
  1648. pstatus );
  1649. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1650. PROPASSERT(IsUnicodeString((WCHAR*)pv, cb));
  1651. // Convert the Unicode string from the property
  1652. // set to Ansi.
  1653. RtlpConvertToMultiByte(
  1654. (WCHAR const *) pv,
  1655. cb,
  1656. CP_ACP, // Use the system default codepage
  1657. &pchConvert,
  1658. &cbcopy,
  1659. pstatus);
  1660. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1661. // 'pv' always has the correct string.
  1662. pv = pchConvert;
  1663. }
  1664. else
  1665. if (CodePage == CP_WINUNICODE)
  1666. {
  1667. // Both the BSTR is unicode in the property set,
  1668. // and must remain unicode in the PropVariant.
  1669. // But byte-swapping may still be necessary.
  1670. CBBYTESWAP( sizeof(WCHAR) );
  1671. }
  1672. #ifdef LITTLEENDIAN
  1673. PROPASSERT( IsOLECHARString((BSTR)pv, cbcopy ));
  1674. #endif
  1675. // Verify that the BSTR is valid.
  1676. if( (cbcopy & (sizeof(OLECHAR)-1)) != 0
  1677. &&
  1678. OLECHAR_IS_UNICODE
  1679. ||
  1680. ((OLECHAR const *)
  1681. pv)[cbcopy/sizeof(OLECHAR) - 1] !=
  1682. ((OLECHAR)'\0') )
  1683. {
  1684. StatusError(
  1685. pstatus,
  1686. "RtlConvertPropertyToVariant:"
  1687. " Invalid BSTR element",
  1688. STATUS_INTERNAL_DB_CORRUPTION);
  1689. goto Exit;
  1690. }
  1691. } // if (pvar->vt == (VT_VECTOR | VT_BSTR))
  1692. // Special LPSTR pre-processing
  1693. else if (pvar->vt == (VT_VECTOR | VT_LPSTR))
  1694. {
  1695. // LPSTRs are always Ansi. If the string
  1696. // is Unicode in the propset, convert now.
  1697. if (CodePage == CP_WINUNICODE)
  1698. {
  1699. // If byte-swapping is necessary, the string from
  1700. // the propset must be swapped before it can be
  1701. // converted to MBCS. If such a conversion
  1702. // is necessary, a new buffer is alloced and
  1703. // put in pchByteSwap. Either way, 'pv' points
  1704. // to the correct string.
  1705. PBSInPlaceAlloc( (WCHAR**) &pv, (WCHAR**) &pchByteSwap,
  1706. pstatus );
  1707. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1708. PROPASSERT(IsUnicodeString((WCHAR*)pv, cb));
  1709. // Convert to Ansi.
  1710. RtlpConvertToMultiByte(
  1711. (WCHAR const *) pv,
  1712. cb,
  1713. CP_ACP, // Use the system default codepage
  1714. &pchConvert,
  1715. &cbcopy,
  1716. pstatus);
  1717. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1718. pv = pchConvert;
  1719. }
  1720. PROPASSERT( IsAnsiString( (CHAR const *)pv, cbcopy ));
  1721. } // else if (pvar->vt == (VT_VECTOR | VT_LPSTR))
  1722. } // if (cb != 0)
  1723. // Allocate memory in the PropVariant and copy
  1724. // the string.
  1725. if( (VT_BSTR | VT_VECTOR) == pvar->vt )
  1726. {
  1727. // For BSTRs, the allocate/copy is performed
  1728. // by SysStringAlloc.
  1729. *ppv = (*UnicodeCallouts.pfnSysAllocString)( (BSTR) pv );
  1730. if (*ppv == NULL)
  1731. {
  1732. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory for BSTR element");
  1733. goto Exit;
  1734. }
  1735. // The BSTR length should be the property length
  1736. // minus the NULL.
  1737. PROPASSERT( BSTRLEN(*ppv) == cbcopy - sizeof(OLECHAR) );
  1738. } // if( VT_BSTR == pvar->vt )
  1739. else
  1740. {
  1741. // Allocate a buffer in the PropVariant
  1742. *ppv = pma->Allocate(max(1, cbcopy));
  1743. if (*ppv == NULL)
  1744. {
  1745. StatusKBufferOverflow(pstatus, "RtlConvertPropertyToVariant: no memory for string element");
  1746. goto Exit;
  1747. }
  1748. // Copy from the propset buffer to the PropVariant
  1749. RtlCopyMemory(*ppv, pv, cbcopy);
  1750. } // if( VT_BSTR == pvar->vt ) ... else
  1751. // If necessary, byte-swap in the PropVariant to get
  1752. // the proper byte-ordering.
  1753. PBSBuffer( *ppv, cbcopy, cbByteSwap );
  1754. // Adjust the PropVar element ptr to user-space (kernel only)
  1755. ADJUSTPOINTER(*ppv, PointerDelta, VOID *);
  1756. // Move, within the propset buffer, to the
  1757. // next element in the vector.
  1758. pbsrc += DwordAlign(cb);
  1759. // Delete the temporary buffers
  1760. delete[] pchByteSwap;
  1761. pchByteSwap = NULL;
  1762. delete [] pchConvert;
  1763. pchConvert = NULL;
  1764. } // if (fConvertToEmpty || cb != 0)
  1765. // Move, within the PropVariant, to the next
  1766. // element in the vector.
  1767. ppv++;
  1768. } // while (cElems-- > 0)
  1769. } // else if (pvar->vt == (VT_VECTOR | VT_CF)) ... else
  1770. } // if (!fPostAllocInit) ... else
  1771. ADJUSTPOINTER(*ppvK, PointerDelta, VOID *);
  1772. } // if (!fConvertToEmpty && cb == 0) ... else
  1773. } // else if (ppv != NULL)
  1774. Exit:
  1775. delete[] pchByteSwap;
  1776. delete [] pchConvert;
  1777. }
  1778. //+---------------------------------------------------------------------------
  1779. // Function: CleanupVariants, private
  1780. //
  1781. // Synopsis: Free all memory used by an array of PROPVARIANT
  1782. //
  1783. // Arguments: [pvar] -- pointer to PROPVARIANT
  1784. // [cprop] -- property count
  1785. // [pma] -- caller's memory free routine
  1786. //
  1787. // Returns: None
  1788. //---------------------------------------------------------------------------
  1789. VOID
  1790. CleanupVariants(
  1791. IN PROPVARIANT *pvar,
  1792. IN ULONG cprop,
  1793. IN PMemoryAllocator *pma)
  1794. {
  1795. while (cprop-- > 0)
  1796. {
  1797. VOID *pv = NULL;
  1798. VOID **ppv = NULL;
  1799. ULONG cElems;
  1800. switch (pvar->vt)
  1801. {
  1802. case VT_CF:
  1803. pv = pvar->pclipdata;
  1804. if (pv != NULL && pvar->pclipdata->pClipData)
  1805. {
  1806. pma->Free(pvar->pclipdata->pClipData);
  1807. }
  1808. break;
  1809. case VT_BLOB:
  1810. case VT_BLOB_OBJECT:
  1811. pv = pvar->blob.pBlobData;
  1812. break;
  1813. case VT_BSTR:
  1814. case VT_CLSID:
  1815. case VT_LPSTR:
  1816. case VT_LPWSTR:
  1817. AssertStringField(puuid); // VT_CLSID
  1818. AssertStringField(bstrVal); // VT_BSTR
  1819. AssertStringField(pszVal); // VT_LPSTR
  1820. AssertStringField(pwszVal); // VT_LPWSTR
  1821. pv = pvar->pszVal;
  1822. break;
  1823. // Vector properties:
  1824. #ifdef PROPVAR_VT_I1
  1825. case VT_VECTOR | VT_I1:
  1826. AssertByteVector(cac); // VT_I1
  1827. #endif
  1828. case VT_VECTOR | VT_UI1:
  1829. case VT_VECTOR | VT_I2:
  1830. case VT_VECTOR | VT_UI2:
  1831. case VT_VECTOR | VT_BOOL:
  1832. case VT_VECTOR | VT_I4:
  1833. case VT_VECTOR | VT_UI4:
  1834. case VT_VECTOR | VT_R4:
  1835. case VT_VECTOR | VT_ERROR:
  1836. case VT_VECTOR | VT_I8:
  1837. case VT_VECTOR | VT_UI8:
  1838. case VT_VECTOR | VT_R8:
  1839. case VT_VECTOR | VT_CY:
  1840. case VT_VECTOR | VT_DATE:
  1841. case VT_VECTOR | VT_FILETIME:
  1842. case VT_VECTOR | VT_CLSID:
  1843. AssertByteVector(caub); // VT_UI1
  1844. AssertShortVector(cai); // VT_I2
  1845. AssertShortVector(caui); // VT_UI2
  1846. AssertShortVector(cabool); // VT_BOOL
  1847. AssertLongVector(cal); // VT_I4
  1848. AssertLongVector(caul); // VT_UI4
  1849. AssertLongVector(caflt); // VT_R4
  1850. AssertLongVector(cascode); // VT_ERROR
  1851. AssertLongLongVector(cah); // VT_I8
  1852. AssertLongLongVector(cauh); // VT_UI8
  1853. AssertLongLongVector(cadbl); // VT_R8
  1854. AssertLongLongVector(cacy); // VT_CY
  1855. AssertLongLongVector(cadate); // VT_DATE
  1856. AssertLongLongVector(cafiletime); // VT_FILETIME
  1857. AssertVarVector(cauuid, sizeof(GUID)); // VT_CLSID
  1858. pv = pvar->cai.pElems;
  1859. break;
  1860. case VT_VECTOR | VT_CF:
  1861. {
  1862. CLIPDATA *pcd;
  1863. cElems = pvar->caclipdata.cElems;
  1864. pv = pcd = pvar->caclipdata.pElems;
  1865. while (cElems-- > 0)
  1866. {
  1867. if (pcd->pClipData != NULL)
  1868. {
  1869. pma->Free(pcd->pClipData);
  1870. }
  1871. pcd++;
  1872. }
  1873. }
  1874. break;
  1875. case VT_VECTOR | VT_BSTR:
  1876. case VT_VECTOR | VT_LPSTR:
  1877. case VT_VECTOR | VT_LPWSTR:
  1878. AssertStringVector(cabstr); // VT_BSTR
  1879. AssertStringVector(calpstr); // VT_LPSTR
  1880. AssertStringVector(calpwstr); // VT_LPWSTR
  1881. cElems = pvar->calpstr.cElems;
  1882. ppv = (VOID **) pvar->calpstr.pElems;
  1883. break;
  1884. case VT_VECTOR | VT_VARIANT:
  1885. CleanupVariants(
  1886. pvar->capropvar.pElems,
  1887. pvar->capropvar.cElems,
  1888. pma);
  1889. pv = pvar->capropvar.pElems;
  1890. break;
  1891. } // switch (pvar->vt)
  1892. if (ppv != NULL) // STRING VECTOR property
  1893. {
  1894. // Save the vector of pointers
  1895. pv = (VOID *) ppv;
  1896. // Free the vector elements
  1897. while (cElems-- > 0)
  1898. {
  1899. if (*ppv != NULL)
  1900. {
  1901. if( (VT_BSTR | VT_VECTOR) == pvar->vt )
  1902. {
  1903. (*UnicodeCallouts.pfnSysFreeString)( (BSTR) *ppv );
  1904. }
  1905. else
  1906. {
  1907. pma->Free((BYTE *) *ppv);
  1908. }
  1909. }
  1910. ppv++;
  1911. }
  1912. // Free the vector of pointers.
  1913. pma->Free(pv);
  1914. pv = NULL;
  1915. } // if (ppv != NULL)
  1916. if (pv != NULL)
  1917. {
  1918. if( VT_BSTR == pvar->vt )
  1919. {
  1920. (*UnicodeCallouts.pfnSysFreeString)( (BSTR) pv );
  1921. }
  1922. else
  1923. {
  1924. pma->Free((BYTE *) pv);
  1925. }
  1926. }
  1927. pvar->vt = VT_EMPTY;
  1928. // Move on to the next PropVar in the vector.
  1929. pvar++;
  1930. } // while (cprop-- > 0)
  1931. }
  1932. //+--------------------------------------------------------------------------
  1933. // Function: PropertyLength
  1934. //
  1935. // Synopsis: compute the length of a property including the variant type
  1936. //
  1937. // Arguments: [pprop] -- property value
  1938. // [cbbuf] -- max length of accessible memory at pprop
  1939. // [flags] -- CPropertySetStream flags
  1940. // [pstatus] -- pointer to NTSTATUS code
  1941. //
  1942. // Returns: length of property
  1943. //---------------------------------------------------------------------------
  1944. ULONG
  1945. PropertyLength(
  1946. SERIALIZEDPROPERTYVALUE const *pprop,
  1947. ULONG cbbuf,
  1948. BYTE flags,
  1949. OUT NTSTATUS *pstatus)
  1950. {
  1951. ULONG const *pl = (ULONG const *) pprop->rgb;
  1952. ULONG cElems = 1;
  1953. ULONG cbremain = cbbuf;
  1954. ULONG cb = 0, cbch;
  1955. BOOLEAN fIllegalType = FALSE;
  1956. *pstatus = STATUS_SUCCESS;
  1957. if (cbremain < CB_SERIALIZEDPROPERTYVALUE)
  1958. {
  1959. StatusOverflow(pstatus, "PropertyLength: dwType");
  1960. goto Exit;
  1961. }
  1962. cbremain -= CB_SERIALIZEDPROPERTYVALUE;
  1963. if( PropByteSwap(pprop->dwType) & VT_VECTOR )
  1964. {
  1965. if (cbremain < sizeof(ULONG))
  1966. {
  1967. StatusOverflow(pstatus, "PropertyLength: cElems");
  1968. goto Exit;
  1969. }
  1970. cbremain -= sizeof(ULONG);
  1971. cElems = PropByteSwap( *pl++ );
  1972. }
  1973. if( PropByteSwap(pprop->dwType) == (VT_VECTOR | VT_VARIANT) )
  1974. {
  1975. while (cElems-- > 0)
  1976. {
  1977. cb = PropertyLength(
  1978. (SERIALIZEDPROPERTYVALUE const *) pl,
  1979. cbremain,
  1980. flags | CPSS_VARIANTVECTOR,
  1981. pstatus);
  1982. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1983. pl = (ULONG const *) Add2ConstPtr(pl, cb);
  1984. cbremain -= cb;
  1985. }
  1986. }
  1987. else
  1988. {
  1989. cbch = sizeof(WCHAR);
  1990. switch( PropByteSwap(pprop->dwType) & VT_TYPEMASK)
  1991. {
  1992. case VT_EMPTY:
  1993. case VT_NULL:
  1994. fIllegalType = (flags & CPSS_VARIANTVECTOR) != 0;
  1995. break;
  1996. #ifdef PROPVAR_VT_I1
  1997. case VT_I1:
  1998. #endif
  1999. case VT_UI1:
  2000. pl = (ULONG const *) Add2ConstPtr(pl, DwordAlign(cElems * sizeof(BYTE)));
  2001. break;
  2002. case VT_I2:
  2003. case VT_UI2:
  2004. case VT_BOOL:
  2005. pl = (ULONG const *) Add2ConstPtr(pl, DwordAlign(cElems * sizeof(USHORT)));
  2006. break;
  2007. case VT_I4:
  2008. case VT_UI4:
  2009. case VT_R4:
  2010. case VT_ERROR:
  2011. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(ULONG));
  2012. break;
  2013. case VT_I8:
  2014. case VT_UI8:
  2015. case VT_R8:
  2016. case VT_CY:
  2017. case VT_DATE:
  2018. case VT_FILETIME:
  2019. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(LONGLONG));
  2020. break;
  2021. case VT_CLSID:
  2022. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(GUID));
  2023. break;
  2024. case VT_BLOB:
  2025. case VT_BLOB_OBJECT:
  2026. // FALLTHROUGH
  2027. case VT_CF:
  2028. case VT_BSTR:
  2029. case VT_LPSTR:
  2030. cbch = sizeof(BYTE);
  2031. // FALLTHROUGH
  2032. case VT_LPWSTR:
  2033. while (cElems-- > 0)
  2034. {
  2035. if (cbremain < sizeof(ULONG) ||
  2036. cbremain < (cb = sizeof(ULONG) + DwordAlign(PropByteSwap(*pl) * cbch)))
  2037. {
  2038. StatusOverflow(pstatus, "PropertyLength: String/BLOB/CF");
  2039. goto Exit;
  2040. }
  2041. #ifdef LITTLEENDIAN
  2042. PROPASSERT(
  2043. (PropByteSwap(pprop->dwType) & VT_TYPEMASK) != VT_LPWSTR
  2044. ||
  2045. IsUnicodeString( (WCHAR const *) &pl[1],
  2046. PropByteSwap(*pl) * sizeof(WCHAR)));
  2047. #endif
  2048. pl = (ULONG const *) Add2ConstPtr(pl, cb);
  2049. cbremain -= cb;
  2050. }
  2051. break;
  2052. default:
  2053. fIllegalType = TRUE;
  2054. break;
  2055. }
  2056. }
  2057. if (fIllegalType)
  2058. {
  2059. StatusInvalidParameter(pstatus, "PropertyLength: Illegal VarType");
  2060. goto Exit;
  2061. }
  2062. cb = (BYTE *) pl - (BYTE *) pprop;
  2063. if (cbbuf < cb)
  2064. {
  2065. StatusOverflow(pstatus, "PropertyLength: cb");
  2066. goto Exit;
  2067. }
  2068. // Make sure PropertyLength works when limited to an exact size buffer.
  2069. PROPASSERT(cb == cbbuf || PropertyLength(pprop, cb, flags, pstatus) == cb);
  2070. // ----
  2071. // Exit
  2072. // ----
  2073. Exit:
  2074. // Normalize the error return value.
  2075. if( !NT_SUCCESS(*pstatus) )
  2076. cb = 0;
  2077. return(cb);
  2078. }
  2079. //+--------------------------------------------------------------------------
  2080. // Function: PBSCopy
  2081. //
  2082. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  2083. // only compile in the BIGENDIAN build. In the
  2084. // LITTLEENDIAN build, they are inlined with NOOP functions.
  2085. //
  2086. // This routine copies the source to the destination,
  2087. // byte-swapping as it copies.
  2088. //
  2089. // Arguments: [VOID*] pvDest
  2090. // Pointer to the target (swapped) buffer.
  2091. // This must be pre-allocated by the caller.
  2092. // [VOID*] pvSource
  2093. // Pointer to the original buffer.
  2094. // [ULONG] cbSize
  2095. // Size in bytes of the buffer.
  2096. // [ULONG] cbByteSwap
  2097. // Size of byte-swapping units.
  2098. //
  2099. // Returns: None.
  2100. //
  2101. //---------------------------------------------------------------------------
  2102. #ifdef BIGENDIAN
  2103. VOID PBSCopy( OUT VOID *pvDest,
  2104. IN VOID const *pvSource,
  2105. IN ULONG cbCopy,
  2106. IN LONG cbByteSwap )
  2107. {
  2108. PROPASSERT( (cbCopy & 1) == 0 );
  2109. PROPASSERT( pvDest != NULL && pvSource != NULL );
  2110. memcpy( pvDest, pvSource, cbCopy );
  2111. PBSBuffer( pvDest, cbCopy, cbByteSwap );
  2112. }
  2113. #endif // BIGENDIAN
  2114. //+--------------------------------------------------------------------------
  2115. // Function: PBSAllocAndCopy
  2116. //
  2117. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  2118. // only compile in the BIGENDIAN build. In the
  2119. // LITTLEENDIAN build, they are inlined with NOOP functions.
  2120. //
  2121. // This routine allocs a buffer, and swaps the bytes from
  2122. // the source buffer into the destination.
  2123. //
  2124. // Arguments: [VOID**] ppvDest (out)
  2125. // On success will point to the swapped buffer.
  2126. // [VOID*] pvSource (in)
  2127. // Pointer to the original buffer.
  2128. // [ULONG] cbSize (in)
  2129. // Size in bytes of the buffer.
  2130. // [LONG] cbByteSwap (in)
  2131. // Size of byte-swapping units.
  2132. // [NTSTATUS*] pstatus (out)
  2133. // NTSTATUS code.
  2134. //
  2135. // Returns: None.
  2136. //
  2137. // Note: The caller is responsible for freeing *ppvDest
  2138. // (using ::delete).
  2139. //
  2140. //---------------------------------------------------------------------------
  2141. #ifdef BIGENDIAN
  2142. VOID PBSAllocAndCopy( OUT VOID **ppvDest,
  2143. IN VOID const *pvSource,
  2144. ULONG cbSize,
  2145. LONG cbByteSwap,
  2146. OUT NTSTATUS *pstatus)
  2147. {
  2148. ULONG cchString;
  2149. // -----
  2150. // Begin
  2151. // -----
  2152. *pstatus = STATUS_SUCCESS;
  2153. PROPASSERT( ppvDest != NULL && pvSource != NULL );
  2154. // Allocate a buffer.
  2155. *ppvDest = new BYTE[ cbSize ];
  2156. if( NULL == *ppvDest )
  2157. {
  2158. *pstatus = STATUS_NO_MEMORY;
  2159. goto Exit;
  2160. }
  2161. // Swap/copy the bytes.
  2162. PBSCopy( *ppvDest, pvSource, cbSize, cbByteSwap );
  2163. // ----
  2164. // Exit
  2165. // ----
  2166. Exit:
  2167. return;
  2168. } // PBSAllocAndCopy
  2169. #endif // BIGENDIAN
  2170. //+--------------------------------------------------------------------------
  2171. // Function: PBSInPlaceAlloc
  2172. //
  2173. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  2174. // only compile in the BIGENDIAN build. In the
  2175. // LITTLEENDIAN build, they are inlined with NOOP functions.
  2176. //
  2177. // This routine takes a WCHAR array, allocates a new buffer,
  2178. // and swaps the original array into the new buffer.
  2179. //
  2180. //
  2181. // Arguments: [WCHAR**] ppwszResult
  2182. // IN: *ppwszResult points to string to be swapped.
  2183. // OUT: *ppwszResult points to the swapped string.
  2184. // [WCHAR**] ppwszBuffer
  2185. // *ppwszBuffer points to the buffer which was allocated
  2186. // for the swapped bytes (should be the same as *ppwszResult).
  2187. // *ppwszBuffer must be NULL in input, and must be freed
  2188. // by the caller (using ::delete).
  2189. // [NTSTATUS*] pstatus
  2190. // NTSTATUS code.
  2191. //
  2192. // Returns: None.
  2193. //
  2194. // On input, *ppwszResult contains the original string.
  2195. // An equivalently sized buffer is allocated in *ppwszBuffer,
  2196. // and *ppwszResult is byte-swapped into it. *ppwszResult
  2197. // is then set to the new *ppwszBuffer.
  2198. //
  2199. // It doesn't appear to useful to have both buffer parameters,
  2200. // but it makes it easier on the caller in certain circumstances;
  2201. // *ppwszResult always points to the correct string, whether the
  2202. // build is BIGENDIAN (alloc & swap takes place) or the build
  2203. // is LITTLEENDIAN (nothing happes, so *ppwszResult continues
  2204. // to point to the proper string). The LITTLEENDIAN version of
  2205. // this function is implemented as an inline routine.
  2206. //
  2207. //---------------------------------------------------------------------------
  2208. #ifdef BIGENDIAN
  2209. VOID PBSInPlaceAlloc( IN OUT WCHAR** ppwszResult,
  2210. OUT WCHAR** ppwszBuffer,
  2211. OUT NTSTATUS *pstatus )
  2212. {
  2213. // ------
  2214. // Locals
  2215. // ------
  2216. WCHAR *pwszNewBuffer;
  2217. // Pointers which will walk through the input buffers.
  2218. WCHAR *pwszOriginal, *pwszSwapped;
  2219. // -----
  2220. // Begin
  2221. // -----
  2222. *pstatus = STATUS_SUCCESS;
  2223. // Allocate a new buffer.
  2224. pwszNewBuffer = new WCHAR[ Prop_wcslen(*ppwszResult) + 1 ];
  2225. if( NULL == pwszNewBuffer )
  2226. {
  2227. *pstatus = STATUS_NO_MEMORY;
  2228. goto Exit;
  2229. }
  2230. // Swap the WCHARs into the new buffer.
  2231. pwszOriginal = *ppwszResult;
  2232. pwszSwapped = pwszNewBuffer;
  2233. do
  2234. {
  2235. *pwszSwapped = PropByteSwap(*pwszOriginal++);
  2236. } while( *pwszSwapped++ != L'\0' );
  2237. // If the caller wants a special pointer to the new buffer,
  2238. // set it now.
  2239. if( NULL != ppwszBuffer )
  2240. {
  2241. PROPASSERT( NULL== *ppwszBuffer );
  2242. *ppwszBuffer = pwszNewBuffer;
  2243. }
  2244. // Also point *ppwszResult to the new buffer.
  2245. *ppwszResult = pwszNewBuffer;
  2246. // ----
  2247. // Exit
  2248. // ----
  2249. Exit:
  2250. return;
  2251. } // PropByteSwap( WCHAR**, WCHAR**, NTSTATUS*)
  2252. #endif // BIGENDIAN
  2253. //+--------------------------------------------------------------------------
  2254. // Function: PBSBuffer
  2255. //
  2256. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  2257. // only compile in the BIGENDIAN build. In the
  2258. // LITTLEENDIAN build, they are inlined with NOOP functions.
  2259. //
  2260. // This routine takes a buffer and byte-swaps it. The caller
  2261. // specifies the size of the buffer, and the granularity of
  2262. // the byte-swapping.
  2263. //
  2264. // Arguments: [VOID*] pv
  2265. // Pointer to the buffer to be swapped.
  2266. // [ULONG] cbSize
  2267. // Size in bytes of the buffer.
  2268. // [ULONG] cbByteSwap
  2269. // Size of byte-swapping units.
  2270. //
  2271. // Returns: None.
  2272. //
  2273. // For example, an array of 4 WORDs could be swapped with:
  2274. //
  2275. // PBSBuffer( (VOID*) aw, 4, sizeof(WORD) );
  2276. //
  2277. //---------------------------------------------------------------------------
  2278. #ifdef BIGENDIAN
  2279. VOID PBSBuffer( IN OUT VOID *pv,
  2280. IN ULONG cbSize,
  2281. IN ULONG cbByteSwap )
  2282. {
  2283. ULONG ulIndex;
  2284. // What kind of swapping should be do?
  2285. switch( cbByteSwap )
  2286. {
  2287. // No swapping required
  2288. case 0:
  2289. case( sizeof(BYTE) ):
  2290. // Nothing to do.
  2291. break;
  2292. // Swap WORDs
  2293. case( sizeof(WORD) ):
  2294. for( ulIndex = 0; ulIndex < cbSize/sizeof(WORD); ulIndex++ )
  2295. ByteSwap( &((WORD*)pv)[ulIndex] );
  2296. break;
  2297. // Swap DWORDs
  2298. case( sizeof(DWORD) ):
  2299. for( ulIndex = 0; ulIndex < cbSize/sizeof(DWORD); ulIndex++ )
  2300. ByteSwap( &((DWORD*)pv)[ulIndex] );
  2301. break;
  2302. // Swap LONGLONGs
  2303. case( sizeof(LONGLONG) ):
  2304. for( ulIndex = 0; ulIndex < cbSize/sizeof(LONGLONG); ulIndex++ )
  2305. ByteSwap( &((LONGLONG*)pv)[ulIndex] );
  2306. break;
  2307. // Swap GUIDs
  2308. case CBBYTESWAP_UID:
  2309. for( ulIndex = 0; ulIndex < cbSize/sizeof(GUID); ulIndex++ )
  2310. ByteSwap( &((GUID*)pv)[ulIndex] );
  2311. break;
  2312. // Error
  2313. default:
  2314. PROPASSERT( !"Invalid generic byte-swap size" );
  2315. }
  2316. } // PropByteSwap( VOID*, ULONG, ULONG )
  2317. #endif // BIGENDIAN
  2318. DEFINE_CBufferAllocator__Allocate