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.

4369 lines
148 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. // History: 15-Aug-95 vich created
  11. // 22-Feb-96 MikeHill Moved DwordRemain to "propmac.hxx".
  12. // 09-May-96 MikeHill Use the 'boolVal' member of PropVariant
  13. // rather than the member named 'bool'.
  14. // 22-May-96 MikeHill Use the caller-provided codepage for
  15. // string conversions, not the system default.
  16. // 06-Jun-96 MikeHill Modify CLIPDATA.cbData to include sizeof
  17. // ulClipFmt.
  18. // 12-Jun-96 MikeHill - Use new BSTR alloc/free routines.
  19. // - Added VT_I1 support (under ifdefs)
  20. // - Bug for VT_CF|VT_VECTOR in RtlConvPropToVar
  21. // 25-Jul-96 MikeHill - Removed Win32 SEH.
  22. // - BSTRs: WCHAR=>OLECHAR
  23. // - Added big-endian support.
  24. // 10-Mar-98 MikeHill - Added support for Variant types except
  25. // for VT_RECORD.
  26. // 06-May-98 MikeHill - Removed usage of UnicodeCallouts.
  27. // - Wrap SafeArray/BSTR calls for delayed-linking.
  28. // - Enforce VT in VT_ARRAYs.
  29. // - Added support for VT_VARIANT|VT_BYREF.
  30. // - Added support for VT_ARRAY|VT_BYREF.
  31. // - Added support for VT_VECTOR|VT_I1.
  32. // - Use CoTaskMem rather than new/delete.
  33. // 11-June-98 MikeHill - Validate elements of arrays & vectors.
  34. //
  35. //---------------------------------------------------------------------------
  36. #include <pch.cxx>
  37. #include <stdio.h>
  38. #ifndef _MAC
  39. #include <ddeml.h> // for CP_WINUNICODE
  40. #endif
  41. #include "propvar.h"
  42. #ifndef newk
  43. #define newk(Tag, pCounter) new
  44. #endif
  45. #if DBGPROP
  46. BOOLEAN
  47. IsUnicodeString(WCHAR const *pwszname, ULONG cb)
  48. {
  49. return( TRUE );
  50. }
  51. BOOLEAN
  52. IsAnsiString(CHAR const *pszname, ULONG cb)
  53. {
  54. return( TRUE );
  55. }
  56. #endif
  57. //+---------------------------------------------------------------------------
  58. // Function: PrpConvertToUnicode, private
  59. //
  60. // Synopsis: Convert a MultiByte string to a Unicode string
  61. //
  62. // Arguments: [pch] -- pointer to MultiByte string
  63. // [cb] -- byte length of MultiByte string
  64. // [CodePage] -- property set codepage
  65. // [ppwc] -- pointer to returned pointer to Unicode string
  66. // [pcb] -- returned byte length of Unicode string
  67. //
  68. // Returns: Nothing
  69. //---------------------------------------------------------------------------
  70. VOID
  71. PrpConvertToUnicode(
  72. IN CHAR const *pch,
  73. IN ULONG cb,
  74. IN USHORT CodePage,
  75. OUT WCHAR **ppwc,
  76. OUT ULONG *pcb,
  77. OUT NTSTATUS *pstatus)
  78. {
  79. WCHAR *pwszName;
  80. *pstatus = STATUS_SUCCESS;
  81. PROPASSERT(pch != NULL);
  82. PROPASSERT(ppwc != NULL);
  83. PROPASSERT(pcb != NULL);
  84. *ppwc = NULL;
  85. *pcb = 0;
  86. ULONG cwcName;
  87. pwszName = NULL;
  88. cwcName = 0;
  89. while (TRUE)
  90. {
  91. cwcName = MultiByteToWideChar(
  92. CodePage,
  93. 0, // dwFlags
  94. pch,
  95. cb,
  96. pwszName,
  97. cwcName);
  98. if (cwcName == 0)
  99. {
  100. CoTaskMemFree( pwszName );
  101. *ppwc = NULL;
  102. // If there was an error, assume that it was a code-page
  103. // incompatibility problem.
  104. StatusError(pstatus, "PrpConvertToUnicode: MultiByteToWideChar error",
  105. STATUS_UNMAPPABLE_CHARACTER);
  106. goto Exit;
  107. }
  108. if (pwszName != NULL)
  109. {
  110. DebugTrace(0, DEBTRACE_PROPERTY, (
  111. "PrpConvertToUnicode: pch='%s'[%x] pwc='%ws'[%x->%x]\n",
  112. pch,
  113. cb,
  114. pwszName,
  115. *pcb,
  116. cwcName * sizeof(WCHAR)));
  117. break;
  118. }
  119. *pcb = cwcName * sizeof(WCHAR);
  120. *ppwc = pwszName = (WCHAR *) CoTaskMemAlloc( *pcb );
  121. if (pwszName == NULL)
  122. {
  123. StatusNoMemory(pstatus, "PrpConvertToUnicode: no memory");
  124. goto Exit;
  125. }
  126. }
  127. // ----
  128. // Exit
  129. // ----
  130. Exit:
  131. return;
  132. }
  133. //+---------------------------------------------------------------------------
  134. // Function: PrpConvertToMultiByte, private
  135. //
  136. // Synopsis: Convert a Unicode string to a MultiByte string
  137. //
  138. // Arguments: [pwc] -- pointer to Unicode string
  139. // [cb] -- byte length of Unicode string
  140. // [CodePage] -- property set codepage
  141. // [ppch] -- pointer to returned pointer to MultiByte string
  142. // [pcb] -- returned byte length of MultiByte string
  143. // [pstatus] -- pointer to NTSTATUS code
  144. //
  145. // Returns: Nothing
  146. //---------------------------------------------------------------------------
  147. VOID
  148. PrpConvertToMultiByte(
  149. IN WCHAR const *pwc,
  150. IN ULONG cb,
  151. IN USHORT CodePage,
  152. OUT CHAR **ppch,
  153. OUT ULONG *pcb,
  154. OUT NTSTATUS *pstatus)
  155. {
  156. ULONG cbName;
  157. CHAR *pszName;
  158. *pstatus = STATUS_SUCCESS;
  159. PROPASSERT(pwc != NULL);
  160. PROPASSERT(ppch != NULL);
  161. PROPASSERT(pcb != NULL);
  162. *ppch = NULL;
  163. *pcb = 0;
  164. // Ensure that cb is valid
  165. if( 0 != (cb % 2) )
  166. {
  167. StatusError(pstatus, "PrpConvertToMultiByte: Odd Unicode string cb",
  168. STATUS_INTERNAL_DB_CORRUPTION);
  169. goto Exit;
  170. }
  171. pszName = NULL;
  172. cbName = 0;
  173. while (TRUE)
  174. {
  175. cbName = WideCharToMultiByte(
  176. CodePage,
  177. 0, // dwFlags
  178. pwc,
  179. cb/sizeof(WCHAR),
  180. pszName,
  181. cbName,
  182. NULL, // lpDefaultChar
  183. NULL); // lpUsedDefaultChar
  184. if (cbName == 0)
  185. {
  186. CoTaskMemFree( pszName );
  187. *ppch = NULL;
  188. // If there was an error, assume that it was a code-page
  189. // incompatibility problem.
  190. StatusError(pstatus, "PrpConvertToMultiByte: WideCharToMultiByte error",
  191. STATUS_UNMAPPABLE_CHARACTER);
  192. goto Exit;
  193. }
  194. if (pszName != NULL)
  195. {
  196. DebugTrace(0, DEBTRACE_PROPERTY, (
  197. "PrpConvertToMultiByte: pwc='%ws'[%x] pch='%s'[%x->%x]\n",
  198. pwc,
  199. cb,
  200. pszName,
  201. *pcb,
  202. cbName));
  203. break;
  204. }
  205. *pcb = cbName;
  206. *ppch = pszName = reinterpret_cast<CHAR*>( CoTaskMemAlloc( cbName ));
  207. if (pszName == NULL)
  208. {
  209. StatusNoMemory(pstatus, "PrpConvertToMultiByte: no memory");
  210. goto Exit;
  211. }
  212. }
  213. // ----
  214. // Exit
  215. // ----
  216. Exit:
  217. return;
  218. }
  219. //+---------------------------------------------------------------------------
  220. //
  221. // Function: SerializeSafeArrayBounds, private
  222. //
  223. // Synopsis: Write the rgsabounds field of a SAFEARRAY to pbdst (if non-NULL).
  224. // Calculate and return the size of the serialized bounds,
  225. // and the total number of elements in the array.
  226. //
  227. //---------------------------------------------------------------------------
  228. NTSTATUS
  229. SerializeSafeArrayBounds( const SAFEARRAY *psa, BYTE *pbdst, ULONG *pcbBounds, ULONG *pcElems )
  230. {
  231. NTSTATUS status = STATUS_SUCCESS;
  232. ULONG ulIndex = 0;
  233. ULONG cDims = PrivSafeArrayGetDim( const_cast<SAFEARRAY*>(psa) );
  234. PROPASSERT( 0 < cDims );
  235. *pcbBounds = 0;
  236. *pcElems = 1;
  237. // Loop through each dimension and get its range
  238. for( ulIndex = 1; ulIndex <= cDims; ulIndex++ )
  239. {
  240. LONG lLowerBound = 0, lUpperBound = 0;
  241. // Get the lower & upper bounds
  242. if( SUCCEEDED( status = PrivSafeArrayGetLBound( const_cast<SAFEARRAY*>(psa), ulIndex, &lLowerBound )))
  243. {
  244. status = PrivSafeArrayGetUBound( const_cast<SAFEARRAY*>(psa), ulIndex, &lUpperBound );
  245. }
  246. if( FAILED(status) )
  247. {
  248. goto Exit;
  249. }
  250. else if( lUpperBound < lLowerBound )
  251. {
  252. status = STATUS_INVALID_PARAMETER;
  253. goto Exit;
  254. }
  255. // Update the total element count
  256. *pcElems *= (lUpperBound - lLowerBound + 1 );
  257. // If we're really serializing, write the current set of bounds
  258. if( NULL != pbdst )
  259. {
  260. // Write the length of this dimension
  261. *(ULONG *) pbdst = (lUpperBound - lLowerBound + 1);
  262. pbdst += sizeof(ULONG);
  263. // Then the lower bound
  264. *(LONG *) pbdst = lLowerBound;
  265. pbdst += sizeof(LONG);
  266. }
  267. }
  268. // Calculate the size of the rgsabound array.
  269. *pcbBounds = sizeof(SAFEARRAYBOUND) * cDims;
  270. Exit:
  271. return( status );
  272. }
  273. ULONG
  274. CalcSafeArrayElements( ULONG cDims, const SAFEARRAYBOUND *rgsaBounds )
  275. {
  276. ULONG cElems = 1; // Multiplicitive identity
  277. for( ULONG i = 0; i < cDims; i++ )
  278. cElems *= rgsaBounds[ i ].cElements;
  279. return( cElems );
  280. }
  281. //+---------------------------------------------------------------------------
  282. // Function: StgConvertVariantToProperty, private
  283. //
  284. // Synopsis: Convert a PROPVARIANT to a SERIALIZEDPROPERTYVALUE
  285. //
  286. // Arguments: [pvar] -- pointer to PROPVARIANT
  287. // [CodePage] -- property set codepage
  288. // [pprop] -- pointer to SERIALIZEDPROPERTYVALUE
  289. // [pcb] -- pointer to remaining stream length,
  290. // updated to actual property size on return
  291. // [pid] -- propid (used if indirect)
  292. // [fVariantVectorOrArray] -- TRUE if recursing on VT_VECTOR | VT_VARIANT
  293. // [pcIndirect] -- pointer to indirect property count
  294. // [pstatus] -- pointer to NTSTATUS code
  295. //
  296. // Returns: NULL if buffer too small, else input [pprop] argument
  297. //---------------------------------------------------------------------------
  298. // Define a macro which sets a variable named 'cbByteSwap', but
  299. // only on big-endian builds. This value is not needed on little-
  300. // endian builds (because byte-swapping is not necessary).
  301. #ifdef BIGENDIAN
  302. #define CBBYTESWAP(cb) cbByteSwap = cb
  303. #elif LITTLEENDIAN
  304. #define CBBYTESWAP(cb)
  305. #else
  306. #error Either BIGENDIAN or LITTLEENDIAN must be set.
  307. #endif
  308. // First, define a wrapper for this function which returns errors
  309. // using NT Exception Handling, rather than returning an NTSTATUS.
  310. #if defined(WINNT)
  311. EXTERN_C SERIALIZEDPROPERTYVALUE * __stdcall
  312. StgConvertVariantToProperty(
  313. IN PROPVARIANT const *pvar,
  314. IN USHORT CodePage,
  315. OPTIONAL OUT SERIALIZEDPROPERTYVALUE *pprop,
  316. IN OUT ULONG *pcb,
  317. IN PROPID pid,
  318. IN BOOLEAN fVector,
  319. OPTIONAL OUT ULONG *pcIndirect)
  320. {
  321. SERIALIZEDPROPERTYVALUE *ppropRet;
  322. NTSTATUS status;
  323. ppropRet = StgConvertVariantToPropertyNoEH(
  324. pvar, CodePage, pprop,
  325. pcb, pid, fVector,
  326. FALSE, // fArray
  327. pcIndirect, NULL, &status );
  328. if (!NT_SUCCESS( status ))
  329. RtlRaiseStatus( status );
  330. return (ppropRet );
  331. }
  332. #endif // #if defined(WINNT)
  333. // Enough for "prop%lu" + L'\0'
  334. //#define CCH_MAX_INDIRECT_NAME (4 + 10 + 1)
  335. // Now define the body of the function, returning errors with an
  336. // NTSTATUS value instead of raising.
  337. SERIALIZEDPROPERTYVALUE *
  338. StgConvertVariantToPropertyNoEH(
  339. IN PROPVARIANT const *pvar,
  340. IN USHORT CodePage,
  341. OPTIONAL OUT SERIALIZEDPROPERTYVALUE *pprop,
  342. IN OUT ULONG *pcb,
  343. IN PROPID pid,
  344. IN BOOLEAN fVector, // Used for recursive calls
  345. IN BOOLEAN fArray, // Used for recursive calls
  346. OPTIONAL OUT ULONG *pcIndirect,
  347. IN OUT OPTIONAL WORD *pwMinFormatRequired,
  348. OUT NTSTATUS *pstatus)
  349. {
  350. *pstatus = STATUS_SUCCESS;
  351. // ------
  352. // Locals
  353. // ------
  354. CHAR *pchConvert = NULL;
  355. ULONG count = 0;
  356. BYTE *pbdst;
  357. ULONG cbch = 0;
  358. ULONG cbchdiv = 0;
  359. ULONG cb = 0;
  360. ULONG ulIndex = 0; // Used as a misc loop control variable
  361. // Size of byte-swapping units (e.g. 2 to swap a WORD).
  362. INT cbByteSwap = 0;
  363. ULONG const *pcount = NULL;
  364. VOID const *pv = NULL;
  365. LONG *pclipfmt = NULL;
  366. BOOLEAN fCheckNullSource;
  367. BOOLEAN fIllegalType = FALSE;
  368. const VOID * const *ppv = NULL;
  369. OLECHAR aocName[ PROPGENPROPERTYNAME_SIZEOF ]; //CCH_MAX_INDIRECT_NAME ];
  370. BOOLEAN fByRef;
  371. const SAFEARRAY *parray = NULL;
  372. const VOID *parraydata = NULL;
  373. ULONG fSafeArrayLocked = FALSE;
  374. ULONG cSafeArrayDims = 0;
  375. IFDBG( HRESULT &hr = *pstatus; )
  376. propITraceStatic( "StgConvertVariantToPropertyNoEH" );
  377. propTraceParameters(( "pprop=%p, CodePage=%d, pvar=%p, pma=%p" ));
  378. // Initialize a local wMinFormatRequired - this is the minimum serialization
  379. // format version required for the data in this property set (e.g., if you
  380. // don't use any of the new NT5 support, you can stay a version 0 property set,
  381. // otherwise you go to version 1).
  382. WORD wMinFormatRequired = (NULL == pwMinFormatRequired)
  383. ? (WORD) PROPSET_WFORMAT_ORIGINAL
  384. : (WORD) *pwMinFormatRequired;
  385. // If this is a byref, then up the min format required.
  386. if( VT_BYREF & pvar->vt )
  387. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  388. // We dereference byrefs. If this is a byref Variant, we can shortcut this
  389. // by simply changing pvar.
  390. while( (VT_BYREF | VT_VARIANT) == pvar->vt )
  391. {
  392. if( NULL == pvar->pvarVal )
  393. {
  394. *pstatus = STATUS_INVALID_PARAMETER;
  395. goto Exit;
  396. }
  397. pvar = pvar->pvarVal;
  398. }
  399. // Now that we've settled on the pvar we're going to convert,
  400. // Jot down some info on it.
  401. fCheckNullSource = (BOOLEAN) ((pvar->vt & VT_VECTOR) != 0);
  402. fByRef = 0 != (pvar->vt & VT_BYREF);
  403. // If this is an array, then validate the VT in the SafeArray itself matches
  404. // pvar->vt.
  405. if( VT_ARRAY & pvar->vt )
  406. {
  407. VARTYPE vtSafeArray = VT_EMPTY;
  408. // It's invalid to have both the array and vector bits set (would it be
  409. // an array of vectors or a vector of arrays?).
  410. if( VT_VECTOR & pvar->vt )
  411. {
  412. StatusInvalidParameter( pstatus, "Both VT_VECTOR and VT_ARRAY set" );
  413. goto Exit;
  414. }
  415. // Arrays require an uplevel property set format
  416. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  417. // Get the Type bit from the SafeArray
  418. if( VT_BYREF & pvar->vt )
  419. {
  420. if( NULL != pvar->pparray && NULL != *pvar->pparray )
  421. {
  422. *pstatus = PrivSafeArrayGetVartype( *pvar->pparray, &vtSafeArray );
  423. if( FAILED(*pstatus) )
  424. goto Exit;
  425. }
  426. }
  427. else if( NULL != pvar->parray )
  428. {
  429. *pstatus = PrivSafeArrayGetVartype( pvar->parray, &vtSafeArray );
  430. if( FAILED(*pstatus) )
  431. goto Exit;
  432. }
  433. if( !NT_SUCCESS(*pstatus) )
  434. goto Exit;
  435. // Ensure the VT read from the property set matches that in the PropVariant.
  436. // It is illegal for these to be different.
  437. if( ( vtSafeArray & VT_TYPEMASK )
  438. !=
  439. ( pvar->vt & VT_TYPEMASK ) )
  440. {
  441. *pstatus = STATUS_INVALID_PARAMETER;
  442. goto Exit;
  443. }
  444. } // if( VT_ARRAY & pvar->vt )
  445. // -------------------------------------------------------
  446. // Analyze the PropVariant, and store information about it
  447. // in fIllegalType, cb, pv, pcount, count, pclipfmt,
  448. // fCheckNullSource, cbch, chchdiv, and ppv.
  449. // -------------------------------------------------------
  450. switch( pvar->vt )
  451. {
  452. case VT_EMPTY:
  453. case VT_NULL:
  454. fIllegalType = fVector || fArray;
  455. break;
  456. case VT_I1 | VT_BYREF:
  457. fIllegalType = fVector || fArray;
  458. case VT_I1:
  459. AssertByteField(cVal); // VT_I1
  460. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  461. cb = sizeof(pvar->bVal);
  462. pv = fByRef ? pvar->pcVal : &pvar->cVal;
  463. break;
  464. case VT_UI1 | VT_BYREF:
  465. fIllegalType = fVector || fArray;
  466. case VT_UI1:
  467. AssertByteField(bVal); // VT_UI1
  468. AssertStringField(pbVal);
  469. cb = sizeof(pvar->bVal);
  470. pv = fByRef ? pvar->pbVal : &pvar->bVal;
  471. break;
  472. case VT_I2 | VT_BYREF:
  473. case VT_UI2 | VT_BYREF:
  474. case VT_BOOL | VT_BYREF:
  475. fIllegalType = fVector || fArray;
  476. case VT_I2:
  477. case VT_UI2:
  478. case VT_BOOL:
  479. AssertShortField(iVal); // VT_I2
  480. AssertStringField(piVal);
  481. AssertShortField(uiVal); // VT_UI2
  482. AssertStringField(puiVal);
  483. AssertShortField(boolVal); // VT_BOOL
  484. cb = sizeof(pvar->iVal);
  485. pv = fByRef ? pvar->piVal : &pvar->iVal;
  486. // If swapping, swap as a WORD
  487. CBBYTESWAP(cb);
  488. break;
  489. case VT_INT | VT_BYREF:
  490. case VT_UINT | VT_BYREF:
  491. fIllegalType = fVector || fArray;
  492. case VT_INT:
  493. case VT_UINT:
  494. fIllegalType |= fVector;
  495. // Fall through
  496. case VT_I4 | VT_BYREF:
  497. case VT_UI4 | VT_BYREF:
  498. case VT_R4 | VT_BYREF:
  499. case VT_ERROR | VT_BYREF:
  500. fIllegalType = fVector || fArray;
  501. case VT_I4:
  502. case VT_UI4:
  503. case VT_R4:
  504. case VT_ERROR:
  505. AssertLongField(lVal); // VT_I4
  506. AssertStringField(plVal);
  507. AssertLongField(intVal); // VT_INT
  508. AssertStringField(pintVal);
  509. AssertLongField(ulVal); // VT_UI4
  510. AssertLongField(uintVal); // VT_UINT
  511. AssertStringField(puintVal);
  512. AssertStringField(pulVal);
  513. AssertLongField(fltVal); // VT_R4
  514. AssertStringField(pfltVal);
  515. AssertLongField(scode); // VT_ERROR
  516. AssertStringField(pscode);
  517. if( VT_INT == (pvar->vt&VT_TYPEMASK) || VT_UINT == (pvar->vt&VT_TYPEMASK) )
  518. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  519. cb = sizeof(pvar->lVal);
  520. pv = fByRef ? pvar->plVal : &pvar->lVal;
  521. // If swapping, swap as a DWORD
  522. CBBYTESWAP(cb);
  523. break;
  524. case VT_FILETIME:
  525. fIllegalType = fArray;
  526. /*
  527. case VT_I8 | VT_BYREF:
  528. case VT_UI8 | VT_BYREF:
  529. fIllegalType = fVector || fArray;
  530. */
  531. case VT_I8:
  532. case VT_UI8:
  533. AssertLongLongField(hVal); // VT_I8
  534. AssertLongLongField(uhVal); // VT_UI8
  535. AssertLongLongField(filetime); // VT_FILETIME
  536. cb = sizeof(pvar->hVal);
  537. pv = &pvar->hVal;
  538. // If swapping, swap each DWORD independently.
  539. CBBYTESWAP(sizeof(DWORD));
  540. break;
  541. case VT_R8 | VT_BYREF:
  542. case VT_CY | VT_BYREF:
  543. case VT_DATE | VT_BYREF:
  544. fIllegalType = fVector || fArray;
  545. case VT_R8:
  546. case VT_CY:
  547. case VT_DATE:
  548. AssertLongLongField(dblVal); // VT_R8
  549. AssertStringField(pdblVal);
  550. AssertLongLongField(cyVal); // VT_CY
  551. AssertStringField(pcyVal);
  552. AssertLongLongField(date); // VT_DATE
  553. AssertStringField(pdate);
  554. cb = sizeof(pvar->dblVal);
  555. pv = fByRef ? pvar->pdblVal : &pvar->dblVal;
  556. // If swapping, swap as a LONGLONG (64 bits).
  557. CBBYTESWAP(cb);
  558. break;
  559. case VT_CLSID:
  560. AssertStringField(puuid); // VT_CLSID
  561. fIllegalType = fArray;
  562. cb = sizeof(GUID);
  563. pv = pvar->puuid;
  564. fCheckNullSource = TRUE;
  565. // If swapping, special handling is required.
  566. CBBYTESWAP( CBBYTESWAP_UID );
  567. break;
  568. case VT_DECIMAL | VT_BYREF:
  569. fIllegalType = fVector || fArray;
  570. case VT_DECIMAL:
  571. fIllegalType |= fVector;
  572. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  573. cb = sizeof(DECIMAL);
  574. pv = fByRef ? pvar->pdecVal : &pvar->decVal;
  575. break;
  576. case VT_CF:
  577. fIllegalType = fArray;
  578. // Validate the PropVariant
  579. if (pvar->pclipdata == NULL
  580. ||
  581. pvar->pclipdata->cbSize < sizeof(pvar->pclipdata->ulClipFmt) )
  582. {
  583. StatusInvalidParameter(pstatus, "StgConvertVariantToProperty: pclipdata NULL");
  584. goto Exit;
  585. }
  586. // How many bytes should we copy?
  587. cb = CBPCLIPDATA( *(pvar->pclipdata) );
  588. // Identify the value for this property's count field.
  589. // (which includes sizeof(ulClipFmt))
  590. count = pvar->pclipdata->cbSize;
  591. pcount = &count;
  592. // Identify the clipdata's format & data
  593. pclipfmt = &pvar->pclipdata->ulClipFmt;
  594. pv = pvar->pclipdata->pClipData;
  595. fCheckNullSource = TRUE;
  596. // Note that no byte-swapping of 'pv' is necessary.
  597. break;
  598. case VT_BLOB:
  599. case VT_BLOB_OBJECT:
  600. fIllegalType = fVector || fArray;
  601. pcount = &pvar->blob.cbSize;
  602. cb = *pcount;
  603. pv = pvar->blob.pBlobData;
  604. fCheckNullSource = TRUE;
  605. // Note that no byte-swapping of 'pv' is necessary.
  606. break;
  607. case VT_VERSIONED_STREAM:
  608. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_VERSTREAM );
  609. // Fall through
  610. case VT_STREAM:
  611. case VT_STREAMED_OBJECT:
  612. case VT_STORAGE:
  613. case VT_STORED_OBJECT:
  614. fIllegalType = fVector || fArray;
  615. if( fIllegalType ) break;
  616. // Does the caller support indirect properties?
  617. if (pcIndirect != NULL)
  618. {
  619. // Yes.
  620. (*pcIndirect)++;
  621. // For indirect properties, we don't write the value
  622. // in 'pvar', we write a substitute value. That value is by
  623. // convention (IPropertyStorage knows to use PROPGENPROPERTYNAME),
  624. // so we don't have to pass the name back to the caller.
  625. PROPGENPROPERTYNAME_CB(aocName, sizeof(aocName), pid);
  626. pv = aocName;
  627. }
  628. // Otherwise, the caller doesn't support indirect properties,
  629. // so we'll take the value from pwszVal
  630. else
  631. {
  632. PROPASSERT(
  633. pvar->pwszVal == NULL ||
  634. IsUnicodeString(pvar->pwszVal, MAXULONG));
  635. pv = pvar->pwszVal;
  636. }
  637. count = 1; // default to forcing an error on NULL pointer
  638. // Jump to the LPSTR/BSTR handling code, but skip the ansi check
  639. goto noansicheck;
  640. break;
  641. case VT_BSTR | VT_BYREF:
  642. fIllegalType = fVector || fArray;
  643. count = 0;
  644. pv = *pvar->pbstrVal;
  645. goto noansicheck;
  646. case VT_LPSTR:
  647. fIllegalType = fArray;
  648. PROPASSERT(
  649. pvar->pszVal == NULL ||
  650. IsAnsiString(pvar->pszVal, MAXULONG));
  651. // FALLTHROUGH
  652. case VT_BSTR:
  653. count = 0; // allow NULL pointer
  654. pv = pvar->pszVal;
  655. noansicheck:
  656. AssertStringField(pwszVal); // VT_STREAM, VT_STREAMED_OBJECT
  657. AssertStringField(pwszVal); // VT_STORAGE, VT_STORED_OBJECT
  658. AssertStringField(bstrVal); // VT_BSTR
  659. AssertStringField(pbstrVal);
  660. AssertStringField(pszVal); // VT_LPSTR
  661. AssertStringField(pVersionedStream); // VT_VERSIONED_STREAM
  662. if( fIllegalType ) break;
  663. // We have the string for an LPSTR, BSTR, or indirect
  664. // property pointed to by 'pv'. Now we'll perform any
  665. // Ansi/Unicode conversions and byte-swapping that's
  666. // necessary (putting the result in 'pv').
  667. if (pv == NULL)
  668. {
  669. fCheckNullSource = TRUE;
  670. }
  671. else if (pvar->vt == VT_LPSTR)
  672. {
  673. count = (ULONG)strlen((char *) pv) + 1;
  674. // If the propset is Unicode, convert the LPSTR to Unicode.
  675. if (CodePage == CP_WINUNICODE)
  676. {
  677. // Convert to Unicode.
  678. PROPASSERT(IsAnsiString((CHAR const *) pv, count));
  679. PrpConvertToUnicode(
  680. (CHAR const *) pv,
  681. count,
  682. CP_ACP, // Variants are in the system codepage
  683. (WCHAR **) &pchConvert,
  684. &count,
  685. pstatus);
  686. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  687. // 'pv' always has the ready-to-serialize string.
  688. pv = pchConvert;
  689. // This unicode string may require byte-swapping.
  690. CBBYTESWAP( sizeof(WCHAR) );
  691. }
  692. } // else if (pvar->vt == VT_LPSTR)
  693. else
  694. {
  695. // If this is a BSTR, increment the count to include
  696. // the string terminator.
  697. if( (~VT_BYREF & pvar->vt) == VT_BSTR )
  698. {
  699. count = BSTRLEN(pv); // (This looks at the count field, not wcslen)
  700. // Verify that the input BSTR is terminated.
  701. if( S_OK != StringCbLengthW((const OLECHAR*)pv, count+sizeof(OLECHAR), NULL ))
  702. {
  703. StatusInvalidParameter(pstatus,
  704. "StgConvertVariantToProperty: bad BSTR null char");
  705. goto Exit;
  706. }
  707. // Increment the count to include the terminator.
  708. count += sizeof(OLECHAR);
  709. }
  710. else
  711. {
  712. count = ((ULONG)Prop_ocslen((OLECHAR *) pv) + 1) * sizeof(OLECHAR);
  713. PROPASSERT(IsOLECHARString((OLECHAR const *) pv, count));
  714. }
  715. // This string is either an indirect property name,
  716. // or a BSTR, both of which could be Ansi or Unicode.
  717. if (CodePage != CP_WINUNICODE // Ansi property set
  718. &&
  719. OLECHAR_IS_UNICODE // The PropVariant is in Unicode
  720. )
  721. {
  722. // A Unicode to Ansi conversion is required.
  723. PROPASSERT( IsUnicodeString( (WCHAR*)pv, count ));
  724. PrpConvertToMultiByte(
  725. (WCHAR const *) pv,
  726. count,
  727. CodePage,
  728. &pchConvert,
  729. &count,
  730. pstatus);
  731. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  732. pv = pchConvert;
  733. }
  734. else
  735. if (CodePage == CP_WINUNICODE // Unicode property set,
  736. &&
  737. !OLECHAR_IS_UNICODE // The PropVariant is in Ansi
  738. )
  739. {
  740. // An Ansi to Unicode conversion is required.
  741. PROPASSERT(IsAnsiString((CHAR const *) pv, count));
  742. PROPASSERT(sizeof(OLECHAR) == sizeof(CHAR));
  743. PrpConvertToUnicode(
  744. (CHAR const *) pv,
  745. count,
  746. CP_ACP, // In-mem BSTR is in system CP
  747. (WCHAR **) &pchConvert,
  748. &count,
  749. pstatus);
  750. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  751. // 'pv' always holds the ready-to-serialize value.
  752. pv = pchConvert;
  753. // This unicode string may require swapping.
  754. CBBYTESWAP( sizeof(WCHAR) );
  755. }
  756. else
  757. if (CodePage == CP_WINUNICODE)
  758. {
  759. // No conversion is required (i.e., both 'pv' and the
  760. // property set are Unicode). But we must remember
  761. // to perform a byte-swap (if byte-swapping is necessary).
  762. CBBYTESWAP( sizeof(WCHAR) );
  763. }
  764. } // if (pv == NULL) ... else if ... else
  765. // Validate 'pv'.
  766. #ifdef LITTLEENDIAN
  767. PROPASSERT( NULL == pv
  768. ||
  769. CodePage == CP_WINUNICODE && IsUnicodeString((WCHAR*)pv, count)
  770. ||
  771. CodePage != CP_WINUNICODE && IsAnsiString((CHAR*)pv, count) );
  772. #endif
  773. cb = count;
  774. pcount = &count;
  775. break;
  776. case VT_LPWSTR:
  777. AssertStringField(pwszVal); // VT_LPWSTR
  778. PROPASSERT(
  779. pvar->pwszVal == NULL ||
  780. IsUnicodeString(pvar->pwszVal, MAXULONG));
  781. fIllegalType = fArray;
  782. pv = pvar->pwszVal;
  783. if (pv == NULL)
  784. {
  785. count = 0;
  786. fCheckNullSource = TRUE;
  787. }
  788. else
  789. {
  790. // Calculate the [length] field.
  791. count = (ULONG)Prop_wcslen(pvar->pwszVal) + 1;
  792. // If byte-swapping will be necessary to get to the serialized
  793. // format, we'll do so in units of WCHARs.
  794. CBBYTESWAP( sizeof(WCHAR) );
  795. }
  796. cb = count * sizeof(WCHAR);
  797. pcount = &count;
  798. break;
  799. /*
  800. case VT_RECORD:
  801. pv = pvar->pvRecord;
  802. pRecInfo = pvar->pRecInfo;
  803. if( NULL == pv )
  804. {
  805. count = 0;
  806. fCheckNullSource = TRUE;
  807. }
  808. else if( NULL == pRecInfo )
  809. {
  810. StatusInvalidParameter( pstatus, "Missing IRecordInfo*" );
  811. goto Exit;
  812. }
  813. cb = 0;
  814. break;
  815. */
  816. // Vector properties:
  817. case VT_VECTOR | VT_I1:
  818. AssertByteVector(cac); // VT_I1
  819. fIllegalType = fArray;
  820. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  821. // Fall through
  822. case VT_VECTOR | VT_UI1:
  823. AssertByteVector(caub); // VT_UI1
  824. fIllegalType = fArray;
  825. pcount = &pvar->caub.cElems;
  826. cb = *pcount * sizeof(pvar->caub.pElems[0]);
  827. pv = pvar->caub.pElems;
  828. break;
  829. case VT_VECTOR | VT_I2:
  830. case VT_VECTOR | VT_UI2:
  831. case VT_VECTOR | VT_BOOL:
  832. AssertShortVector(cai); // VT_I2
  833. AssertShortVector(caui); // VT_UI2
  834. AssertShortVector(cabool); // VT_BOOL
  835. fIllegalType = fArray;
  836. pcount = &pvar->cai.cElems;
  837. cb = *pcount * sizeof(pvar->cai.pElems[0]);
  838. pv = pvar->cai.pElems;
  839. // If swapping, swap as WORDs
  840. CBBYTESWAP(sizeof(pvar->cai.pElems[0]));
  841. break;
  842. case VT_VECTOR | VT_I4:
  843. case VT_VECTOR | VT_UI4:
  844. case VT_VECTOR | VT_R4:
  845. case VT_VECTOR | VT_ERROR:
  846. AssertLongVector(cal); // VT_I4
  847. AssertLongVector(caul); // VT_UI4
  848. AssertLongVector(caflt); // VT_R4
  849. AssertLongVector(cascode); // VT_ERROR
  850. fIllegalType = fArray;
  851. pcount = &pvar->cal.cElems;
  852. cb = *pcount * sizeof(pvar->cal.pElems[0]);
  853. pv = pvar->cal.pElems;
  854. // If swapping, swap as DWORDs
  855. CBBYTESWAP(sizeof(pvar->cal.pElems[0]));
  856. break;
  857. case VT_VECTOR | VT_I8:
  858. case VT_VECTOR | VT_UI8:
  859. case VT_VECTOR | VT_FILETIME:
  860. AssertLongLongVector(cah); // VT_I8
  861. AssertLongLongVector(cauh); // VT_UI8
  862. AssertLongLongVector(cafiletime);// VT_FILETIME
  863. fIllegalType = fArray;
  864. pcount = &pvar->cah.cElems;
  865. cb = *pcount * sizeof(pvar->cah.pElems[0]);
  866. pv = pvar->cah.pElems;
  867. // If swapping, swap as DWORDs
  868. CBBYTESWAP(sizeof(DWORD));
  869. break;
  870. case VT_VECTOR | VT_R8:
  871. case VT_VECTOR | VT_CY:
  872. case VT_VECTOR | VT_DATE:
  873. AssertLongLongVector(cadbl); // VT_R8
  874. AssertLongLongVector(cacy); // VT_CY
  875. AssertLongLongVector(cadate); // VT_DATE
  876. fIllegalType = fArray;
  877. pcount = &pvar->cah.cElems;
  878. cb = *pcount * sizeof(pvar->cadbl.pElems[0]);
  879. pv = pvar->cadbl.pElems;
  880. // If swapping, swap as LONGLONGs (8 bytes)
  881. CBBYTESWAP(sizeof(pvar->cadbl.pElems[0]));
  882. break;
  883. case VT_VECTOR | VT_CLSID:
  884. AssertVarVector(cauuid, sizeof(GUID));
  885. fIllegalType = fArray;
  886. pcount = &pvar->cauuid.cElems;
  887. cb = *pcount * sizeof(pvar->cauuid.pElems[0]);
  888. pv = pvar->cauuid.pElems;
  889. // If swapping, special handling is required.
  890. CBBYTESWAP( CBBYTESWAP_UID );
  891. break;
  892. case VT_VECTOR | VT_CF:
  893. fIllegalType = fArray;
  894. cbch = sizeof(CLIPDATA);
  895. cbchdiv = sizeof(BYTE);
  896. goto stringvector;
  897. case VT_VECTOR | VT_BSTR:
  898. case VT_VECTOR | VT_LPSTR:
  899. fIllegalType = fArray;
  900. cbchdiv = cbch = sizeof(BYTE);
  901. goto stringvector;
  902. case VT_VECTOR | VT_LPWSTR:
  903. fIllegalType = fArray;
  904. cbchdiv = cbch = sizeof(WCHAR);
  905. goto stringvector;
  906. case VT_VECTOR | VT_VARIANT:
  907. fIllegalType = fArray;
  908. cbch = MAXULONG;
  909. stringvector:
  910. AssertVarVector(caclipdata, sizeof(CLIPDATA)); // VT_CF
  911. AssertStringVector(cabstr); // VT_BSTR
  912. AssertStringVector(calpstr); // VT_LPSTR
  913. AssertStringVector(calpwstr); // VT_LPWSTR
  914. AssertVarVector(capropvar, sizeof(PROPVARIANT));// VT_VARIANT
  915. pcount = &pvar->calpstr.cElems;
  916. ppv = (VOID **) pvar->calpstr.pElems;
  917. break;
  918. case VT_ARRAY | VT_BSTR:
  919. case VT_ARRAY | VT_BSTR | VT_BYREF:
  920. fIllegalType = fVector || fArray;
  921. cbchdiv = cbch = sizeof(BYTE);
  922. cb = 1;
  923. // Fall through
  924. case VT_ARRAY | VT_VARIANT:
  925. case VT_ARRAY | VT_VARIANT | VT_BYREF:
  926. fIllegalType = fVector || fArray;
  927. if( 0 == cbch )
  928. cbch = MAXULONG;
  929. pcount = &count;
  930. case VT_ARRAY | VT_I1:
  931. case VT_ARRAY | VT_I1 | VT_BYREF:
  932. case VT_ARRAY | VT_UI1:
  933. case VT_ARRAY | VT_UI1 | VT_BYREF:
  934. case VT_ARRAY | VT_I2:
  935. case VT_ARRAY | VT_I2 | VT_BYREF:
  936. case VT_ARRAY | VT_UI2:
  937. case VT_ARRAY | VT_UI2 | VT_BYREF:
  938. case VT_ARRAY | VT_BOOL:
  939. case VT_ARRAY | VT_BOOL | VT_BYREF:
  940. case VT_ARRAY | VT_I4:
  941. case VT_ARRAY | VT_I4 | VT_BYREF:
  942. case VT_ARRAY | VT_UI4:
  943. case VT_ARRAY | VT_UI4 | VT_BYREF:
  944. /*
  945. case VT_ARRAY | VT_I8:
  946. case VT_ARRAY | VT_I8 | VT_BYREF:
  947. case VT_ARRAY | VT_UI8:
  948. case VT_ARRAY | VT_UI8 | VT_BYREF:
  949. */
  950. case VT_ARRAY | VT_INT:
  951. case VT_ARRAY | VT_INT | VT_BYREF:
  952. case VT_ARRAY | VT_UINT:
  953. case VT_ARRAY | VT_UINT | VT_BYREF:
  954. case VT_ARRAY | VT_R4:
  955. case VT_ARRAY | VT_R4 | VT_BYREF:
  956. case VT_ARRAY | VT_ERROR:
  957. case VT_ARRAY | VT_ERROR | VT_BYREF:
  958. case VT_ARRAY | VT_DECIMAL:
  959. case VT_ARRAY | VT_DECIMAL | VT_BYREF:
  960. case VT_ARRAY | VT_R8:
  961. case VT_ARRAY | VT_R8 | VT_BYREF:
  962. case VT_ARRAY | VT_CY:
  963. case VT_ARRAY | VT_CY | VT_BYREF:
  964. case VT_ARRAY | VT_DATE:
  965. case VT_ARRAY | VT_DATE | VT_BYREF:
  966. fIllegalType = fVector || fArray;
  967. if( fIllegalType ) break;
  968. wMinFormatRequired = (WORD) max( wMinFormatRequired, PROPSET_WFORMAT_EXPANDED_VTS );
  969. parray = (VT_BYREF & pvar->vt) ? *pvar->pparray : pvar->parray;
  970. if( NULL == parray )
  971. cb = 0;
  972. else
  973. {
  974. // Get a pointer to the raw data
  975. *pstatus = PrivSafeArrayAccessData( const_cast<SAFEARRAY*>(parray), const_cast<void**>(&parraydata) );
  976. if( FAILED(*pstatus) ) goto Exit;
  977. fSafeArrayLocked = TRUE;
  978. pv = parraydata;
  979. ppv = static_cast<const void* const*>(pv);
  980. // Determine the dimension count and element size
  981. cSafeArrayDims = PrivSafeArrayGetDim( const_cast<SAFEARRAY*>(parray) );
  982. cb = PrivSafeArrayGetElemsize( const_cast<SAFEARRAY*>(parray) );
  983. PROPASSERT( 0 != cb );
  984. if( 0 == cSafeArrayDims )
  985. {
  986. StatusInvalidParameter( pstatus, "Zero-length safearray dimension" );
  987. goto Exit;
  988. }
  989. // Determine the number of elements, and the total size of parraydata
  990. count = CalcSafeArrayElements( cSafeArrayDims, parray->rgsabound );
  991. cb *= count;
  992. }
  993. break;
  994. default:
  995. propDbg(( DEB_IWARN, "StgConvertVariantToProperty: unsupported vt=%d\n", pvar->vt));
  996. *pstatus = STATUS_NOT_SUPPORTED;
  997. goto Exit;
  998. } // switch (pvar->vt)
  999. // ---------------------------------------------------------
  1000. // Serialize the property into the property set (pprop->rgb)
  1001. // ---------------------------------------------------------
  1002. // At this point we've analyzed the PropVariant, and stored
  1003. // information about it in various local variables. Now we
  1004. // can use this information to serialize the propvar.
  1005. // Early exit if this is an illegal type.
  1006. if (fIllegalType)
  1007. {
  1008. propDbg(( DEB_ERROR, "vt=%d\n", pvar->vt ));
  1009. StatusInvalidParameter(pstatus, "StgConvertVariantToProperty: Illegal VarType");
  1010. goto Exit;
  1011. }
  1012. // Set pbdst to point into the serialization buffer, or to
  1013. // NULL if there is no such buffer.
  1014. if (pprop == NULL)
  1015. {
  1016. pbdst = NULL;
  1017. }
  1018. else
  1019. {
  1020. pbdst = pprop->rgb;
  1021. }
  1022. // Is this an Array/Vector of Strings/Variants/CFs?
  1023. if (cbch != 0)
  1024. {
  1025. // Yes.
  1026. PROPASSERT(pcount != NULL);
  1027. PROPASSERT(*pcount == 0 || ppv != NULL);
  1028. PROPASSERT(0 == cbByteSwap);
  1029. // Start calculating the serialized size. Include the sizes
  1030. // of the VT.
  1031. cb = sizeof(ULONG);
  1032. // Is this an Array or Vector of Variants?
  1033. if( cbch != MAXULONG )
  1034. {
  1035. // No. Include each element's length field.
  1036. cb += *pcount * sizeof(ULONG);
  1037. }
  1038. // For vectors, write the element count
  1039. if( VT_VECTOR & pvar->vt )
  1040. {
  1041. cb += sizeof(ULONG);
  1042. // Do we have room to write it?
  1043. if( *pcb < cb )
  1044. {
  1045. // No. But we'll continue to calculate the cb
  1046. pprop = NULL;
  1047. }
  1048. else if( pprop != NULL )
  1049. {
  1050. *(ULONG *) pbdst = PropByteSwap(*pcount);
  1051. pbdst += sizeof(ULONG);
  1052. }
  1053. } // if( VT_VECTOR & pvar->vt )
  1054. // For arrays, write the dimension count, features, and element size
  1055. else if( NULL != parray )
  1056. {
  1057. PROPASSERT( VT_ARRAY & pvar->vt );
  1058. ULONG cbBounds = 0, cElems = 0;
  1059. // Allow for the VarType & dimension count
  1060. cb += sizeof(DWORD);
  1061. cb += sizeof(UINT);
  1062. PROPASSERT( sizeof(DWORD) >= sizeof(VARTYPE) );
  1063. // Allow for the rgsaBounds
  1064. *pstatus = SerializeSafeArrayBounds( parray, NULL, &cbBounds, &cElems );
  1065. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1066. cb += cbBounds;
  1067. // Do we have room to write this?
  1068. if( *pcb < cb )
  1069. {
  1070. // No, but continue to calc cb
  1071. pprop = NULL;
  1072. }
  1073. else if( NULL != pprop )
  1074. {
  1075. // Yes, we have room. Write the safearray header data.
  1076. PROPASSERT( sizeof(UINT) == sizeof(ULONG) );
  1077. // Write the SafeArray's internal vartype. We'll write the real pvar->vt
  1078. // at the bottom of this routine.
  1079. *(DWORD *) pbdst = 0;
  1080. *(VARTYPE *)pbdst = PropByteSwap( static_cast<VARTYPE>(pvar->vt & VT_TYPEMASK) );
  1081. pbdst += sizeof(DWORD);
  1082. // Write the dimension count
  1083. *(UINT *)pbdst = PropByteSwap(cSafeArrayDims);
  1084. pbdst += sizeof(UINT);
  1085. // Write the bounds
  1086. *pstatus = SerializeSafeArrayBounds( parray, pbdst, &cbBounds, &cElems );
  1087. pbdst += cbBounds;
  1088. }
  1089. } // if( VT_VECTOR & pvar->vt ) ... else if
  1090. // Walk through the vector/array and write the elements.
  1091. for( ulIndex = *pcount; ulIndex > 0; ulIndex-- )
  1092. {
  1093. ULONG cbcopy = 0;
  1094. const PROPVARIANT *ppropvarT;
  1095. // Switch on the size of the element.
  1096. switch (cbch)
  1097. {
  1098. //
  1099. // VT_VARIANT, VT_VECTOR
  1100. //
  1101. case MAXULONG:
  1102. cbcopy = MAXULONG;
  1103. // Perform a recursive serialization
  1104. StgConvertVariantToPropertyNoEH(
  1105. (PROPVARIANT *) ppv,
  1106. CodePage,
  1107. NULL,
  1108. &cbcopy,
  1109. PID_ILLEGAL,
  1110. (VT_VECTOR & pvar->vt) ? TRUE : FALSE,
  1111. (VT_ARRAY & pvar->vt) ? TRUE : FALSE,
  1112. NULL,
  1113. &wMinFormatRequired,
  1114. pstatus);
  1115. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1116. break;
  1117. //
  1118. // VT_CF
  1119. //
  1120. case sizeof(CLIPDATA):
  1121. // We copy cbSize-sizeof(ulClipFmt) bytes.
  1122. if( ((CLIPDATA *) ppv)->cbSize < sizeof(ULONG) )
  1123. {
  1124. StatusInvalidParameter(pstatus, "StgConvertVariantToProperty: short cbSize on VT_CF");
  1125. goto Exit;
  1126. }
  1127. else
  1128. {
  1129. cbcopy = CBPCLIPDATA( *(CLIPDATA*) ppv );
  1130. }
  1131. // But increment cb to to include sizeof(ulClipFmt)
  1132. cb += sizeof(ULONG);
  1133. break;
  1134. //
  1135. // VT_LPWSTR
  1136. //
  1137. case sizeof(WCHAR):
  1138. if (*ppv != NULL)
  1139. {
  1140. PROPASSERT(IsUnicodeString((WCHAR const *) *ppv, MAXULONG));
  1141. cbcopy = ((ULONG)Prop_wcslen((WCHAR *) *ppv) + 1) * sizeof(WCHAR);
  1142. pv = *ppv;
  1143. // If byte-swapping is necessary, swap in units of WCHARs
  1144. CBBYTESWAP( sizeof(WCHAR) );
  1145. }
  1146. break;
  1147. //
  1148. // VT_LPSTR/VT_BSTR
  1149. //
  1150. default:
  1151. PROPASSERT(cbch == sizeof(BYTE));
  1152. PROPASSERT(pchConvert == NULL);
  1153. if (*ppv != NULL)
  1154. {
  1155. pv = *ppv;
  1156. // Is this a BSTR?
  1157. if( VT_BSTR == (VT_TYPEMASK & pvar->vt) )
  1158. {
  1159. // Initialize the # bytes to copy.
  1160. cbcopy = BSTRLEN(pv);
  1161. // Verify that the BSTR is terminated.
  1162. if( S_OK != StringCbLengthW((const OLECHAR*)pv, cbcopy+sizeof(OLECHAR), NULL ))
  1163. {
  1164. StatusInvalidParameter(pstatus,
  1165. "StgConvertVariantToProperty: bad BSTR array null char");
  1166. goto Exit;
  1167. }
  1168. // Also copy the string terminator.
  1169. cbcopy += sizeof(OLECHAR);
  1170. // If the propset and the BSTR are in mismatched
  1171. // codepages (one's Unicode, the other's Ansi),
  1172. // correct the BSTR now. In any case, the correct
  1173. // string is in 'pv'.
  1174. if (CodePage != CP_WINUNICODE // Ansi property set
  1175. &&
  1176. OLECHAR_IS_UNICODE) // Unicode BSTR
  1177. {
  1178. PROPASSERT(IsUnicodeString((WCHAR*)pv, cbcopy));
  1179. PrpConvertToMultiByte(
  1180. (WCHAR const *) pv,
  1181. cbcopy,
  1182. CodePage,
  1183. &pchConvert,
  1184. &cbcopy,
  1185. pstatus);
  1186. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1187. pv = pchConvert;
  1188. }
  1189. else
  1190. if (CodePage == CP_WINUNICODE // Unicode property set
  1191. &&
  1192. !OLECHAR_IS_UNICODE) // Ansi BSTRs
  1193. {
  1194. PROPASSERT(IsAnsiString((CHAR const *) pv, cbcopy));
  1195. PrpConvertToUnicode(
  1196. (CHAR const *) pv,
  1197. cbcopy,
  1198. CP_ACP, // In-mem BSTR is in system CP
  1199. (WCHAR **) &pchConvert,
  1200. &cbcopy,
  1201. pstatus);
  1202. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1203. // The Unicode string must have the proper byte order
  1204. CBBYTESWAP( sizeof(WCHAR) );
  1205. pv = pchConvert;
  1206. }
  1207. else
  1208. if (CodePage == CP_WINUNICODE )
  1209. {
  1210. // Both the BSTR and the property set are Unicode.
  1211. // No conversion is required, but byte-swapping
  1212. // is (if byte-swapping is enabled).
  1213. CBBYTESWAP( sizeof(WCHAR) );
  1214. }
  1215. } // if( VT_BSTR == (VT_TYPEMASK & pvar->vt) )
  1216. // Otherwise it's an LPSTR
  1217. else
  1218. {
  1219. PROPASSERT(IsAnsiString((char const *) pv, MAXULONG));
  1220. PROPASSERT(pvar->vt == (VT_VECTOR | VT_LPSTR));
  1221. cbcopy = (ULONG)strlen((char *) pv) + 1; // + trailing null
  1222. if (CodePage == CP_WINUNICODE)
  1223. {
  1224. PROPASSERT(IsAnsiString(
  1225. (CHAR const *) pv,
  1226. cbcopy));
  1227. PrpConvertToUnicode(
  1228. (CHAR const *) pv,
  1229. cbcopy,
  1230. CP_ACP,
  1231. (WCHAR **) &pchConvert,
  1232. &cbcopy,
  1233. pstatus);
  1234. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1235. // If byte-swapping, we'll do so with the WCHARs
  1236. CBBYTESWAP( sizeof(WCHAR) );
  1237. pv = pchConvert;
  1238. }
  1239. } // if (pvar->vt == (VT_VECTOR | VT_BSTR)) ... else
  1240. } // if (*ppv != NULL)
  1241. // In the end, pv should be in the codepage of
  1242. // the property set.
  1243. #ifdef LITTLEENDIAN
  1244. PROPASSERT( NULL == pv
  1245. ||
  1246. CodePage == CP_WINUNICODE && IsUnicodeString((WCHAR*)pv, cbcopy)
  1247. ||
  1248. CodePage != CP_WINUNICODE && IsAnsiString((CHAR*)pv, cbcopy));
  1249. #endif
  1250. break;
  1251. } // switch (cbch)
  1252. // Add the size of this vector element to the property total
  1253. cb += DwordAlign(cbcopy);
  1254. // Will there be enough room for this vector element?
  1255. if (*pcb < cb)
  1256. {
  1257. // No - we'll continue (thus calculating the total size
  1258. // necessary), but we won't write to the caller's buffer.
  1259. pprop = NULL;
  1260. }
  1261. // Is this a vector or array of Variants?
  1262. if (cbch == MAXULONG)
  1263. {
  1264. // Yes. Convert this variant.
  1265. if (pprop != NULL)
  1266. {
  1267. StgConvertVariantToPropertyNoEH(
  1268. (PROPVARIANT *) ppv,
  1269. CodePage,
  1270. (SERIALIZEDPROPERTYVALUE *) pbdst,
  1271. &cbcopy,
  1272. PID_ILLEGAL,
  1273. (VT_VECTOR & pvar->vt) ? TRUE : FALSE,
  1274. (VT_ARRAY & pvar->vt) ? TRUE : FALSE,
  1275. NULL,
  1276. &wMinFormatRequired,
  1277. pstatus);
  1278. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1279. pbdst += cbcopy;
  1280. }
  1281. ppv = (VOID **) Add2Ptr(ppv, sizeof(PROPVARIANT));
  1282. } // if (cbch == MAXULONG)
  1283. else
  1284. {
  1285. // This is a vector/array of strings or clipformats
  1286. PROPASSERT(
  1287. cbch == sizeof(BYTE) ||
  1288. cbch == sizeof(WCHAR) ||
  1289. cbch == sizeof(CLIPDATA));
  1290. PROPASSERT(cbchdiv == sizeof(BYTE) || cbchdiv == sizeof(WCHAR));
  1291. // Are we writing the serialized property?
  1292. if (pprop != NULL)
  1293. {
  1294. ULONG cbVectOrArrayElement;
  1295. // Calculate the length of the vector/array element.
  1296. cbVectOrArrayElement = (ULONG) cbcopy/cbchdiv;
  1297. // Is this a ClipData?
  1298. if( cbch == sizeof(CLIPDATA) )
  1299. {
  1300. // Adjust the length to include sizeof(ulClipFmt)
  1301. cbVectOrArrayElement += sizeof(ULONG);
  1302. // Write the vector element length.
  1303. *(ULONG *) pbdst = PropByteSwap( cbVectOrArrayElement );
  1304. // Advance pbdst & write the clipboard format.
  1305. pbdst += sizeof(ULONG);
  1306. *(ULONG *) pbdst = PropByteSwap( ((CLIPDATA *) ppv)->ulClipFmt );
  1307. }
  1308. else
  1309. {
  1310. // Write the vector element length.
  1311. *(ULONG *) pbdst = PropByteSwap( cbVectOrArrayElement );
  1312. }
  1313. // Advance pbdst & write the property data.
  1314. pbdst += sizeof(ULONG);
  1315. RtlCopyMemory(
  1316. pbdst,
  1317. cbch == sizeof(CLIPDATA)?
  1318. ((CLIPDATA *) ppv)->pClipData :
  1319. pv,
  1320. cbcopy);
  1321. // Zero out the pad bytes.
  1322. RtlZeroMemory(pbdst + cbcopy, DwordRemain(cbcopy));
  1323. // If byte-swapping is necessary, do so now.
  1324. PBSBuffer( pbdst, DwordAlign(cbcopy), cbByteSwap );
  1325. // Advance pbdst to the next property.
  1326. pbdst += DwordAlign(cbcopy);
  1327. } // if (pprop != NULL)
  1328. // Advance ppv to point into the PropVariant at the
  1329. // next element in the array.
  1330. if (cbch == sizeof(CLIPDATA))
  1331. {
  1332. ppv = (VOID **) Add2Ptr(ppv, sizeof(CLIPDATA));
  1333. }
  1334. else
  1335. {
  1336. ppv++;
  1337. CoTaskMemFree( pchConvert );
  1338. pchConvert = NULL;
  1339. }
  1340. } // if (cbch == MAXULONG) ... else
  1341. } // for (cElems = *pcount; cElems > 0; cElems--)
  1342. } // if (cbch != 0) // VECTOR/ARRAY of STRING/VARIANT/CF properties
  1343. else
  1344. {
  1345. // This isn't an array or a vector, or the elements of the array/vector
  1346. // aren't Strings, Variants, or CFs.
  1347. ULONG cbCopy = cb;
  1348. // Adjust cb (the total serialized buffer size) for
  1349. // pre-data.
  1350. if( pvar->vt != VT_EMPTY )
  1351. { // Allow for the VT
  1352. cb += sizeof(ULONG);
  1353. }
  1354. if( pcount != NULL )
  1355. { // Allow for the count field
  1356. cb += sizeof(ULONG);
  1357. }
  1358. if( pclipfmt != NULL )
  1359. { // Allow for the ulClipFmt field.
  1360. cb += sizeof(ULONG);
  1361. }
  1362. if( pvar->vt == VT_VERSIONED_STREAM )
  1363. {
  1364. // Allow for the version guid
  1365. cb += sizeof(pvar->pVersionedStream->guidVersion);
  1366. }
  1367. if( VT_ARRAY & pvar->vt )
  1368. {
  1369. // Allow for SafeArray header info
  1370. cb += sizeof(DWORD); // VT
  1371. cb += sizeof(UINT); // Dimension count
  1372. PROPASSERT( sizeof(DWORD) >= sizeof(VARTYPE) );
  1373. // Allow for the SafeArray bounds vector
  1374. ULONG cbBounds = 0, cElems = 0;
  1375. *pstatus = SerializeSafeArrayBounds( parray, NULL, &cbBounds, &cElems );
  1376. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1377. cb += cbBounds;
  1378. }
  1379. /*
  1380. if( VT_RECORD == (VT_TYPEMASK & pvar->vt) )
  1381. {
  1382. // Allow for the recinfo guids.
  1383. cb += sizeof(GUID); // Type library ID
  1384. cb += sizeof(WORD); // Major version
  1385. cb += sizeof(WORD); // Minor version
  1386. cb += sizeof(LCID); // Type library Locale ID
  1387. cb += sizeof(GUID); // Type info ID
  1388. PROPASSERT( sizeof(WORD) == sizeof(USHORT) ); // Size of major/minor versions
  1389. PROPASSERT( NULL == pcount );
  1390. }
  1391. */
  1392. // Is there room in the caller's buffer?
  1393. if( *pcb < cb )
  1394. { // No - calculate cb but don't write anything.
  1395. pprop = NULL;
  1396. }
  1397. // 'pv' should point to the source data. If it does, then
  1398. // we'll copy it into the property set. If it doesn't but
  1399. // it should, then we'll report an error.
  1400. if (pv != NULL || fCheckNullSource)
  1401. {
  1402. ULONG cbZero = DwordRemain(cbCopy);
  1403. // Do we have a destination (propset) buffer?
  1404. if (pprop != NULL)
  1405. {
  1406. // Copy the GUID for a VT_VERSIONED_STREAM
  1407. if( pvar->vt == VT_VERSIONED_STREAM )
  1408. {
  1409. if( NULL != pvar->pVersionedStream )
  1410. *reinterpret_cast<GUID*>(pbdst) = pvar->pVersionedStream->guidVersion;
  1411. else
  1412. *reinterpret_cast<GUID*>(pbdst) = GUID_NULL;
  1413. PropByteSwap( reinterpret_cast<GUID*>(pbdst) );
  1414. pbdst += sizeof(pvar->pVersionedStream->guidVersion);
  1415. }
  1416. // Does this property have a count field?
  1417. if( pcount != NULL )
  1418. {
  1419. // Write the count & advance pbdst
  1420. *(ULONG *) pbdst = PropByteSwap( *pcount );
  1421. pbdst += sizeof(ULONG);
  1422. }
  1423. // Copy the clipfmt for a VT_CF
  1424. if( pclipfmt != NULL )
  1425. {
  1426. PROPASSERT(pvar->vt == VT_CF);
  1427. // Write the ClipFormat & advance pbdst
  1428. *(ULONG *) pbdst = PropByteSwap( (DWORD) *pclipfmt );
  1429. pbdst += sizeof(ULONG);
  1430. }
  1431. // Write the array info
  1432. if( (VT_ARRAY & pvar->vt) && NULL != parray )
  1433. {
  1434. ULONG cbBounds = 0, cElems = 0;
  1435. PROPASSERT( NULL == pcount && NULL == pclipfmt );
  1436. PROPASSERT( NULL != parray );
  1437. PROPASSERT( 0 != cSafeArrayDims );
  1438. PROPASSERT( VT_ARRAY & pvar->vt );
  1439. PROPASSERT( sizeof(UINT) == sizeof(ULONG) );
  1440. *(DWORD *) pbdst = 0;
  1441. *(VARTYPE *)pbdst = PropByteSwap( static_cast<VARTYPE>(pvar->vt & VT_TYPEMASK) );
  1442. pbdst += sizeof(DWORD);
  1443. *(UINT *)pbdst = PropByteSwap(cSafeArrayDims);
  1444. pbdst += sizeof(UINT);
  1445. *pstatus = SerializeSafeArrayBounds( parray, pbdst, &cbBounds, &cElems );
  1446. pbdst += cbBounds;
  1447. }
  1448. } // if (pprop != NULL)
  1449. // Are we missing the source data?
  1450. if (pv == NULL)
  1451. {
  1452. // The Source pointer is NULL. If cbCopy != 0, the passed
  1453. // VARIANT is not properly formed.
  1454. if (cbCopy != 0)
  1455. {
  1456. StatusInvalidParameter(pstatus, "StgConvertVariantToProperty: bad NULL");
  1457. goto Exit;
  1458. }
  1459. }
  1460. else if (pprop != NULL)
  1461. {
  1462. // We have a non-NULL source & destination.
  1463. // First, copy the bytes from the former to the latter.
  1464. RtlCopyMemory(pbdst, pv, cbCopy);
  1465. // Then, if necessary, swap the bytes in the property
  1466. // set (leaving the PropVariant bytes untouched).
  1467. PBSBuffer( (VOID*) pbdst, cbCopy, cbByteSwap );
  1468. // If this is a decimal, zero-out the reserved word at the front
  1469. // (typically, this is actually the VarType, because of the
  1470. // way in which a decimal is stored in a Variant).
  1471. if( VT_DECIMAL == (~VT_BYREF & pvar->vt) )
  1472. *(WORD *) pbdst = 0;
  1473. }
  1474. // Did we write the serialization?
  1475. if (pprop != NULL)
  1476. {
  1477. // Zero the padding bytes.
  1478. RtlZeroMemory(pbdst + cbCopy, cbZero);
  1479. // Canonicalize VARIANT_BOOLs. We do this here because
  1480. // we don't want to muck with the caller's buffer directly.
  1481. if ((pvar->vt & ~VT_VECTOR) == VT_BOOL)
  1482. {
  1483. VARIANT_BOOL *pvb = (VARIANT_BOOL *) pbdst;
  1484. VARIANT_BOOL *pvbEnd = &pvb[cbCopy/sizeof(*pvb)];
  1485. while (pvb < pvbEnd)
  1486. {
  1487. if (*pvb
  1488. &&
  1489. PropByteSwap(*pvb) != VARIANT_TRUE)
  1490. {
  1491. DebugTrace(0, DEBTRACE_ERROR, (
  1492. "Patching VARIANT_TRUE value: %hx --> %hx\n",
  1493. *pvb,
  1494. VARIANT_TRUE));
  1495. *pvb = PropByteSwap( (VARIANT_BOOL) VARIANT_TRUE );
  1496. }
  1497. pvb++;
  1498. }
  1499. }
  1500. } // if (pprop != NULL)
  1501. }
  1502. } // if (cbch != 0) ... else // non - STRING/VARIANT/CF VECTOR property
  1503. // Set the VT in the serialized buffer now that all size
  1504. // checks completed.
  1505. if (pprop != NULL && pvar->vt != VT_EMPTY)
  1506. {
  1507. // When byte-swapping the VT, treat it as a DWORD
  1508. // (it's a WORD in the PropVariant, but a DWORD when
  1509. // serialized).
  1510. pprop->dwType = PropByteSwap( static_cast<DWORD>(~VT_BYREF & pvar->vt) );
  1511. }
  1512. // Update the caller's copy of the total size.
  1513. *pcb = DwordAlign(cb);
  1514. Exit:
  1515. if( fSafeArrayLocked )
  1516. {
  1517. PROPASSERT( NULL != parraydata );
  1518. PROPASSERT( NULL != parray );
  1519. PrivSafeArrayUnaccessData( const_cast<SAFEARRAY*>(parray) );
  1520. parraydata = NULL;
  1521. }
  1522. /*
  1523. if( NULL != pTypeInfo )
  1524. pTypeInfo->Release();
  1525. if( NULL != pTypeLib )
  1526. pTypeLib->Release();
  1527. */
  1528. if( NULL != pwMinFormatRequired )
  1529. *pwMinFormatRequired = wMinFormatRequired;
  1530. CoTaskMemFree( pchConvert );
  1531. return(pprop);
  1532. }
  1533. //+---------------------------------------------------------------------------
  1534. // Function: StgConvertPropertyToVariant, private
  1535. //
  1536. // Synopsis: Convert a SERIALIZEDPROPERTYVALUE to a PROPVARIANT
  1537. //
  1538. // Arguments: [pprop] -- pointer to SERIALIZEDPROPERTYVALUE
  1539. // [PointerDelta] -- adjustment to pointers to get user addresses
  1540. // [fConvertNullStrings] -- map NULL strings to empty strings
  1541. // [CodePage] -- property set codepage
  1542. // [pvar] -- pointer to PROPVARIANT
  1543. // [pma] -- caller's memory allocation routine
  1544. // [pstatus] -- pointer to NTSTATUS code
  1545. //
  1546. // Returns: TRUE if property is an indirect property type
  1547. //
  1548. // NOTE: This routine assumes that pprop points to a semi-valid
  1549. // serialized property value. That is, pprop points to
  1550. // a property value, and its buffer is long enough to hold
  1551. // the buffer. This is ensured by calling PropertyLength first.
  1552. // PropertyLength doesn't, however, ensure that individual fields
  1553. // are correct, only that the length prefix is valid. E.g.
  1554. // it doesn't check the individual fields of a VT_CF, it doesn't
  1555. // verify that strings are terminated, etc.
  1556. //
  1557. //---------------------------------------------------------------------------
  1558. #ifdef KERNEL
  1559. #define ADJUSTPOINTER(ptr, delta, type) (ptr) = (type) Add2Ptr((ptr), (delta))
  1560. #else
  1561. #define ADJUSTPOINTER(ptr, delta, type)
  1562. #endif
  1563. // First, define a wrapper for this function which returns errors
  1564. // using NT Exception Handling, rather than returning an NTSTATUS.
  1565. // This is done for backwards compatibility with old CI implementations.
  1566. #if defined(WINNT)
  1567. EXTERN_C BOOLEAN __stdcall
  1568. StgConvertPropertyToVariant(
  1569. IN SERIALIZEDPROPERTYVALUE const *pprop,
  1570. IN USHORT CodePage,
  1571. OUT PROPVARIANT *pvar,
  1572. IN PMemoryAllocator *pma)
  1573. {
  1574. BOOLEAN boolRet;
  1575. NTSTATUS status;
  1576. boolRet = StgConvertPropertyToVariantNoEH(
  1577. pprop, -1, CodePage, pvar,
  1578. pma, &status );
  1579. if (!NT_SUCCESS( status ))
  1580. RtlRaiseStatus( status );
  1581. return (boolRet);
  1582. }
  1583. #endif // #if defined(WINNT)
  1584. // Now define the body of the function, returning errors with an
  1585. // NTSTATUS value instead of raising.
  1586. BOOLEAN
  1587. StgConvertPropertyToVariantNoEH(
  1588. IN SERIALIZEDPROPERTYVALUE const *pprop,
  1589. IN ULONG cbprop,
  1590. IN USHORT CodePage,
  1591. OUT PROPVARIANT *pvar,
  1592. IN PMemoryAllocator *pma,
  1593. OUT NTSTATUS *pstatus)
  1594. {
  1595. *pstatus = STATUS_SUCCESS;
  1596. // ------
  1597. // Locals
  1598. // ------
  1599. BOOLEAN fIndirect = FALSE;
  1600. // Buffers which must be freed before exiting.
  1601. CHAR *pchConvert = NULL, *pchByteSwap = NULL;
  1602. VOID **ppv = NULL;
  1603. VOID *pv = NULL;
  1604. const VOID *pvCountedString = NULL;
  1605. VOID *pvSafeArrayData = NULL;
  1606. SAFEARRAY *psa = NULL;
  1607. BOOL fSafeArrayLocked = FALSE;
  1608. ULONG cbskip = sizeof(ULONG);
  1609. ULONG cb = 0;
  1610. // Size of byte-swapping units (must be signed).
  1611. INT cbByteSwap = 0;
  1612. BOOLEAN fPostAllocInit = FALSE;
  1613. BOOLEAN fNullLegal = (BOOLEAN) ( (PropByteSwap(pprop->dwType) & VT_VECTOR) != 0 );
  1614. IFDBG( HRESULT &hr = *pstatus; )
  1615. propITraceStatic( "StgConvertPropertyToVariantNoEH" );
  1616. propTraceParameters(( "pprop=%p, CodePage=%d, pvar=%p, pma=%p" ));
  1617. // ---------------------------------------------------------
  1618. // Based on the VT, calculate ppv, pv, cbskip,
  1619. // cb, fPostAllocInit, cbCheck, fNullLegal
  1620. // ---------------------------------------------------------
  1621. // Set the VT in the PropVariant. Note that in 'pprop' it's a
  1622. // DWORD, but it's a WORD in 'pvar'.
  1623. pvar->vt = (VARTYPE) PropByteSwap(pprop->dwType);
  1624. if( VT_BYREF & pvar->vt )
  1625. {
  1626. // ByRef's are always indirected on their way to the property set.
  1627. // Thus we should never see a VT_BYREF in serialized form.
  1628. StatusError( pstatus, "StgConvertPropertyToVariant found VT_BYREF",
  1629. STATUS_INTERNAL_DB_CORRUPTION );
  1630. goto Exit;
  1631. }
  1632. //
  1633. // Switch on the type and set cb, pv, etc. The information stored in these
  1634. // is subsequently used to do most of the work. In many cases, we can just do
  1635. // a copy at the end of the switch, we copy cb bytes from pprop->rgb into the buffer
  1636. // pointed to by pv (which points into the output propvariant). If an allocation
  1637. // must be done, ppv points to the location in the propvariant that should hold
  1638. // the buffer, so we allocate at buffer at *ppv, then copy cb bytes into it.
  1639. //
  1640. switch( pvar->vt )
  1641. {
  1642. case VT_EMPTY:
  1643. case VT_NULL:
  1644. break;
  1645. case VT_I1:
  1646. //AssertByteField(cVal); // VT_I1
  1647. cb = sizeof(pvar->cVal);
  1648. pv = &pvar->cVal;
  1649. break;
  1650. case VT_UI1:
  1651. AssertByteField(bVal); // VT_UI1
  1652. cb = sizeof(pvar->bVal);
  1653. pv = &pvar->bVal;
  1654. break;
  1655. case VT_I2:
  1656. case VT_UI2:
  1657. case VT_BOOL:
  1658. AssertShortField(iVal); // VT_I2
  1659. AssertShortField(uiVal); // VT_UI2
  1660. AssertShortField(boolVal); // VT_BOOL
  1661. cb = sizeof(pvar->iVal);
  1662. pv = &pvar->iVal;
  1663. // If swapping, swap as a WORD
  1664. CBBYTESWAP(cb);
  1665. break;
  1666. case VT_I4:
  1667. case VT_INT:
  1668. case VT_UI4:
  1669. case VT_UINT:
  1670. case VT_R4:
  1671. case VT_ERROR:
  1672. AssertLongField(lVal); // VT_I4
  1673. //AssertLongField(intVal) // VT_INT
  1674. AssertLongField(ulVal); // VT_UI4
  1675. //AssertLongField(uintVal); // VT_UINT
  1676. AssertLongField(fltVal); // VT_R4
  1677. AssertLongField(scode); // VT_ERROR
  1678. cb = sizeof(pvar->lVal);
  1679. pv = &pvar->lVal;
  1680. // If swapping, swap as a DWORD
  1681. CBBYTESWAP(cb);
  1682. break;
  1683. case VT_I8:
  1684. case VT_UI8:
  1685. case VT_FILETIME:
  1686. AssertLongLongField(hVal); // VT_I8
  1687. AssertLongLongField(uhVal); // VT_UI8
  1688. AssertLongLongField(filetime); // VT_FILETIME
  1689. cb = sizeof(pvar->hVal);
  1690. pv = &pvar->hVal;
  1691. // If swapping, swap as a pair of DWORDs
  1692. CBBYTESWAP(sizeof(DWORD));
  1693. break;
  1694. case VT_R8:
  1695. case VT_CY:
  1696. case VT_DATE:
  1697. AssertLongLongField(dblVal); // VT_R8
  1698. AssertLongLongField(cyVal); // VT_CY
  1699. AssertLongLongField(date); // VT_DATE
  1700. cb = sizeof(pvar->dblVal);
  1701. pv = &pvar->dblVal;
  1702. // If swapping, swap as a LONGLONG
  1703. CBBYTESWAP(cb);
  1704. break;
  1705. case VT_CLSID:
  1706. AssertStringField(puuid); // VT_CLSID
  1707. cb = sizeof(GUID);
  1708. ppv = (VOID **) &pvar->puuid;
  1709. cbskip = 0;
  1710. // If swapping, special handling is required
  1711. CBBYTESWAP( CBBYTESWAP_UID );
  1712. break;
  1713. case VT_DECIMAL:
  1714. //AssertVarField(decVal, sizeof(DECIMAL)); // VT_DECIMAL
  1715. cb = sizeof(DECIMAL);
  1716. pv = (VOID *) &pvar->decVal;
  1717. #ifdef BIGENDIAN
  1718. #error Big-Endian support required
  1719. // Define CBBYTESWAP_DECIMAL, and add support for it below
  1720. //CBBYTESWAP( CBBYTESWAP_DECIMAL );
  1721. #endif
  1722. break;
  1723. case VT_CF:
  1724. // Allocate a CLIPDATA buffer. Init-zero it so that we can
  1725. // do a safe cleanup should an early-exist be necessary.
  1726. pvar->pclipdata = (CLIPDATA *) pma->Allocate(sizeof(CLIPDATA));
  1727. if (pvar->pclipdata == NULL)
  1728. {
  1729. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory for CF");
  1730. goto Exit;
  1731. }
  1732. RtlZeroMemory( pvar->pclipdata, sizeof(CLIPDATA) );
  1733. // Set the size (includes sizeof(ulClipFmt))
  1734. pvar->pclipdata->cbSize = PropByteSwap( ((CLIPDATA *) pprop->rgb)->cbSize );
  1735. if( pvar->pclipdata->cbSize < sizeof(pvar->pclipdata->ulClipFmt) )
  1736. {
  1737. StatusError(pstatus, "StgConvertPropertyToVariant: Invalid VT_CF cbSize",
  1738. STATUS_INTERNAL_DB_CORRUPTION);
  1739. goto Exit;
  1740. }
  1741. // Set the # bytes-to-copy. We can't use the CBPCLIPDATA macro
  1742. // here because it assumes that the CLIPDATA parameter is correctly
  1743. // byte-swapped.
  1744. cb = PropByteSwap( *(DWORD*) pprop->rgb ) - sizeof(pvar->pclipdata->ulClipFmt);
  1745. // Set the ClipFormat itself.
  1746. pvar->pclipdata->ulClipFmt = PropByteSwap( ((CLIPDATA *) pprop->rgb)->ulClipFmt );
  1747. // Prepare for the alloc & copy. Put the buffer pointer
  1748. // in pClipData, & skip the ulClipFmt in the copy.
  1749. ppv = (VOID **) &pvar->pclipdata->pClipData;
  1750. cbskip += sizeof(ULONG);
  1751. // It's legal for cb to be 0.
  1752. fNullLegal = TRUE;
  1753. // Adjust to the user-mode pointer (Kernel only)
  1754. ADJUSTPOINTER(pvar->pclipdata, PointerDelta, CLIPDATA *);
  1755. break;
  1756. case VT_BLOB:
  1757. case VT_BLOB_OBJECT:
  1758. cb = pvar->blob.cbSize = PropByteSwap( *(ULONG *) pprop->rgb );
  1759. ppv = (VOID **) &pvar->blob.pBlobData;
  1760. fNullLegal = TRUE;
  1761. break;
  1762. case VT_VERSIONED_STREAM:
  1763. // Allocate the first buffer (which will point to the stream)
  1764. pvar->pVersionedStream = reinterpret_cast<LPVERSIONEDSTREAM>( pma->Allocate( sizeof(*pvar->pVersionedStream) ));
  1765. if (pvar->pVersionedStream == NULL)
  1766. {
  1767. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory for VersionedStream");
  1768. goto Exit;
  1769. }
  1770. RtlZeroMemory( pvar->pVersionedStream, sizeof(*pvar->pVersionedStream) );
  1771. // Read the GUID (the PropertyLength function has already
  1772. // validated that the buffer is big enough to read the GUID
  1773. // and counted string.
  1774. pvar->pVersionedStream->guidVersion = *reinterpret_cast<const GUID*>( pprop->rgb );
  1775. PropByteSwap( &pvar->pVersionedStream->guidVersion );
  1776. // A buffer will be allocated and the stream name put into *ppv.
  1777. ppv = reinterpret_cast<void**>( &pvar->pVersionedStream->pStream );
  1778. // Point to the beginning of the string
  1779. pvCountedString = Add2Ptr( pprop->rgb, sizeof(GUID) );
  1780. // When copying the string, we will skip the guid
  1781. cbskip += sizeof(GUID);
  1782. // Fall through
  1783. case VT_STREAM:
  1784. case VT_STREAMED_OBJECT:
  1785. case VT_STORAGE:
  1786. case VT_STORED_OBJECT:
  1787. fIndirect = TRUE;
  1788. goto lpstr;
  1789. case VT_BSTR:
  1790. case VT_LPSTR:
  1791. lpstr:
  1792. AssertStringField(pszVal); // VT_STREAM, VT_STREAMED_OBJECT
  1793. AssertStringField(pszVal); // VT_STORAGE, VT_STORED_OBJECT
  1794. AssertStringField(bstrVal); // VT_BSTR
  1795. AssertStringField(pszVal); // VT_LPSTR
  1796. // The string to be converted is loaded into pvCountedString
  1797. if( NULL == pvCountedString )
  1798. pvCountedString = reinterpret_cast<const void*>(pprop->rgb);
  1799. // [length field] bytes should be allocated
  1800. cb = PropByteSwap( *(ULONG *) pvCountedString );
  1801. // When a buffer is allocated, its pointer will go
  1802. // in *ppv.
  1803. if( NULL == ppv )
  1804. ppv = (VOID **) &pvar->pszVal;
  1805. // Is this a non-empty string?
  1806. if (cb != 0)
  1807. {
  1808. // Yes, non-empty. If the serialized string is Unicode, ensure
  1809. // that the cb is even
  1810. if( CodePage == CP_WINUNICODE
  1811. &&
  1812. 0 != (cb % 2) )
  1813. {
  1814. StatusError(pstatus, "StgConvertPropertyToVariant: Odd Unicode string cb",
  1815. STATUS_INTERNAL_DB_CORRUPTION);
  1816. goto Exit;
  1817. }
  1818. // Also ensure that the string is terminated
  1819. if( CodePage == CP_WINUNICODE )
  1820. {
  1821. WCHAR *pwsz = (WCHAR *) Add2ConstPtr(pvCountedString, sizeof(ULONG));
  1822. //if( L'\0' != pwsz[ cb/sizeof(WCHAR) - 1 ] )
  1823. if( S_OK != StringCbLengthW(pwsz, cb, NULL ))
  1824. {
  1825. StatusError(pstatus, "StgConvertPropertyToVariant: Unterminated string",
  1826. STATUS_INTERNAL_DB_CORRUPTION );
  1827. goto Exit;
  1828. }
  1829. }
  1830. else
  1831. {
  1832. CHAR *psz = (CHAR *) Add2ConstPtr(pvCountedString, sizeof(ULONG));
  1833. //if( '\0' != psz[ cb - 1 ] )
  1834. if( S_OK != StringCbLengthA(psz, cb, NULL ))
  1835. {
  1836. StatusError(pstatus, "StgConvertPropertyToVariant: Unterminated string",
  1837. STATUS_INTERNAL_DB_CORRUPTION );
  1838. goto Exit;
  1839. }
  1840. }
  1841. // Is the serialized value one that should be
  1842. // an Ansi string in the PropVariant (if so it might require conversion)?
  1843. if (pvar->vt == VT_LPSTR // It's an LPSTR (always Ansi), or
  1844. ||
  1845. !OLECHAR_IS_UNICODE ) // PropVariant strings are Ansi (Mac)
  1846. {
  1847. // If the propset is Unicode, we must do a
  1848. // conversion to Ansi.
  1849. if (CodePage == CP_WINUNICODE)
  1850. {
  1851. WCHAR *pwsz = (WCHAR *) Add2ConstPtr(pvCountedString, sizeof(ULONG));
  1852. // If necessary, swap the WCHARs. 'pwsz' will point to
  1853. // the correct (system-endian) string either way. If an
  1854. // alloc is necessary, 'pchByteSwap' will point to the new
  1855. // buffer.
  1856. PBSInPlaceAlloc( &pwsz, (WCHAR**) &pchByteSwap, pstatus );
  1857. if( !NT_SUCCESS( *pstatus )) goto Exit;
  1858. PROPASSERT(IsUnicodeString( pwsz, cb));
  1859. // Convert the properly-byte-ordered string in 'pwsz'
  1860. // into MBCS, putting the result in pchConvert.
  1861. // This routine will validate that cb is even.
  1862. PrpConvertToMultiByte(
  1863. pwsz,
  1864. cb,
  1865. CP_ACP, // Use the system default codepage
  1866. &pchConvert,
  1867. &cb,
  1868. pstatus);
  1869. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1870. }
  1871. } // if (pvar->vt == VT_LPSTR) ...
  1872. // Otherwise, even though this string may be
  1873. // Ansi in the Property Set, it must be Unicode
  1874. // in the PropVariant.
  1875. else
  1876. {
  1877. // If necessary, convert to Unicode
  1878. if (CodePage != CP_WINUNICODE)
  1879. {
  1880. PROPASSERT(
  1881. IsAnsiString(
  1882. (CHAR const *)
  1883. Add2ConstPtr(pvCountedString, sizeof(ULONG)),
  1884. cb));
  1885. PrpConvertToUnicode(
  1886. (CHAR const *)
  1887. Add2ConstPtr(pvCountedString, sizeof(ULONG)),
  1888. cb,
  1889. CodePage,
  1890. (WCHAR **) &pchConvert,
  1891. &cb,
  1892. pstatus);
  1893. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  1894. } // if (CodePage != CP_WINUNICODE)
  1895. else
  1896. {
  1897. // The value is Unicode both the property set
  1898. // and the PropVariant. If byte-swapping is
  1899. // necessary, we'll do so in units of WCHARs.
  1900. CBBYTESWAP( sizeof(WCHAR) );
  1901. }
  1902. } // if (pvar->vt == VT_LPSTR) ... else
  1903. } // if (cb != 0)
  1904. fNullLegal = TRUE;
  1905. break;
  1906. case VT_LPWSTR:
  1907. fNullLegal = TRUE;
  1908. AssertStringField(pwszVal); // VT_LPWSTR
  1909. // Show where buffer needs to be allocated.
  1910. ppv = (VOID **) &pvar->pwszVal;
  1911. // Calculate the length of the Unicode string. Put the total number
  1912. // of bytes for this property in cbCheck.
  1913. cb = PropByteSwap( *(ULONG *) pprop->rgb ) * sizeof(WCHAR);
  1914. // Ensure the string is null-terminated.
  1915. if( 0 != cb )
  1916. {
  1917. WCHAR *pwsz = (WCHAR *) Add2ConstPtr(pprop->rgb, sizeof(ULONG));
  1918. //if( L'\0' != pwsz[ cb/sizeof(WCHAR) - 1 ] )
  1919. if( S_OK != StringCbLengthW(pwsz, cb, NULL ))
  1920. {
  1921. StatusError(pstatus, "StgConvertPropertyToVariant: Unterminated string",
  1922. STATUS_INTERNAL_DB_CORRUPTION );
  1923. goto Exit;
  1924. }
  1925. }
  1926. // If byte-swapping will be necessary, do so for the WCHARs
  1927. CBBYTESWAP( sizeof(WCHAR) );
  1928. break;
  1929. //
  1930. // VT_VECTOR types are handled by a recursive call.
  1931. //
  1932. case VT_VECTOR | VT_I1:
  1933. //AssertByteVector(cac); // VT_I1
  1934. case VT_VECTOR | VT_UI1:
  1935. AssertByteVector(caub); // VT_UI1
  1936. pvar->caub.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1937. cb = pvar->caub.cElems * sizeof(pvar->caub.pElems[0]);
  1938. ppv = (VOID **) &pvar->caub.pElems;
  1939. break;
  1940. case VT_VECTOR | VT_I2:
  1941. case VT_VECTOR | VT_UI2:
  1942. case VT_VECTOR | VT_BOOL:
  1943. AssertShortVector(cai); // VT_I2
  1944. AssertShortVector(caui); // VT_UI2
  1945. AssertShortVector(cabool); // VT_BOOL
  1946. pvar->cai.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1947. cb = pvar->cai.cElems * sizeof(pvar->cai.pElems[0]);
  1948. ppv = (VOID **) &pvar->cai.pElems;
  1949. // If swapping, swap as a WORD
  1950. CBBYTESWAP(sizeof(pvar->cai.pElems[0]));
  1951. break;
  1952. case VT_VECTOR | VT_I4:
  1953. case VT_VECTOR | VT_UI4:
  1954. case VT_VECTOR | VT_R4:
  1955. case VT_VECTOR | VT_ERROR:
  1956. AssertLongVector(cal); // VT_I4
  1957. AssertLongVector(caul); // VT_UI4
  1958. AssertLongVector(caflt); // VT_R4
  1959. AssertLongVector(cascode); // VT_ERROR
  1960. pvar->cal.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1961. cb = pvar->cal.cElems * sizeof(pvar->cal.pElems[0]);
  1962. ppv = (VOID **) &pvar->cal.pElems;
  1963. // If byte swapping, swap as DWORDs
  1964. CBBYTESWAP(sizeof(pvar->cal.pElems[0]));
  1965. break;
  1966. case VT_VECTOR | VT_I8:
  1967. case VT_VECTOR | VT_UI8:
  1968. case VT_VECTOR | VT_FILETIME:
  1969. AssertLongLongVector(cah); // VT_I8
  1970. AssertLongLongVector(cauh); // VT_UI8
  1971. AssertLongLongVector(cafiletime); // VT_FILETIME
  1972. pvar->cah.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1973. cb = pvar->cah.cElems * sizeof(pvar->cah.pElems[0]);
  1974. ppv = (VOID **) &pvar->cah.pElems;
  1975. // If byte swapping, swap as DWORDs
  1976. CBBYTESWAP(sizeof(DWORD));
  1977. break;
  1978. case VT_VECTOR | VT_R8:
  1979. case VT_VECTOR | VT_CY:
  1980. case VT_VECTOR | VT_DATE:
  1981. AssertLongLongVector(cadbl); // VT_R8
  1982. AssertLongLongVector(cacy); // VT_CY
  1983. AssertLongLongVector(cadate); // VT_DATE
  1984. pvar->cadbl.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1985. cb = pvar->cadbl.cElems * sizeof(pvar->cadbl.pElems[0]);
  1986. ppv = (VOID **) &pvar->cadbl.pElems;
  1987. // If byte swapping, swap as LONGLONGs
  1988. CBBYTESWAP(sizeof(pvar->cadbl.pElems[0]));
  1989. break;
  1990. case VT_VECTOR | VT_CLSID:
  1991. AssertVarVector(cauuid, sizeof(GUID));
  1992. pvar->cauuid.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  1993. cb = pvar->cauuid.cElems * sizeof(pvar->cauuid.pElems[0]);
  1994. ppv = (VOID **) &pvar->cauuid.pElems;
  1995. // If byte swapping, special handling is required.
  1996. CBBYTESWAP( CBBYTESWAP_UID );
  1997. break;
  1998. case VT_VECTOR | VT_CF:
  1999. // Set the count of clipdatas
  2000. pvar->caclipdata.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  2001. // How much should we allocate for caclipdata.pElems, & where
  2002. // should that buffer pointer go?
  2003. cb = pvar->caclipdata.cElems * sizeof(pvar->caclipdata.pElems[0]);
  2004. ppv = (VOID **) &pvar->caclipdata.pElems;
  2005. // We need to do work after pElems is allocated.
  2006. fPostAllocInit = TRUE;
  2007. break;
  2008. case VT_VECTOR | VT_BSTR:
  2009. case VT_VECTOR | VT_LPSTR:
  2010. AssertStringVector(cabstr); // VT_BSTR
  2011. AssertStringVector(calpstr); // VT_LPSTR
  2012. // Put the element count in the PropVar
  2013. pvar->calpstr.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  2014. // An array of cElems pointers should be alloced
  2015. cb = pvar->calpstr.cElems * sizeof(CHAR*);
  2016. // Show where the array of pointers should go.
  2017. ppv = (VOID **) &pvar->calpstr.pElems;
  2018. // Additional allocs will be necessary after the vector
  2019. // is alloced.
  2020. fPostAllocInit = TRUE;
  2021. break;
  2022. case VT_VECTOR | VT_LPWSTR:
  2023. AssertStringVector(calpwstr); // VT_LPWSTR
  2024. pvar->calpwstr.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  2025. cb = pvar->calpwstr.cElems * sizeof(WCHAR *);
  2026. ppv = (VOID **) &pvar->calpwstr.pElems;
  2027. fPostAllocInit = TRUE;
  2028. break;
  2029. case VT_VECTOR | VT_VARIANT:
  2030. AssertVariantVector(capropvar); // VT_VARIANT
  2031. pvar->capropvar.cElems = PropByteSwap( *(ULONG *) pprop->rgb );
  2032. cb = pvar->capropvar.cElems * sizeof(PROPVARIANT);
  2033. ppv = (VOID **) &pvar->capropvar.pElems;
  2034. fPostAllocInit = TRUE;
  2035. break;
  2036. //
  2037. // VT_ARRAY (SafeArray) types are handled by a recursive call
  2038. //
  2039. case VT_ARRAY | VT_BSTR:
  2040. cbskip = 0;
  2041. cb = sizeof(BSTR); // (BSTR is really a pointer)
  2042. ppv = (VOID**) &pvar->parray;
  2043. fPostAllocInit = TRUE;
  2044. break;
  2045. case VT_ARRAY | VT_VARIANT:
  2046. cbskip = 0;
  2047. cb = sizeof(PROPVARIANT);
  2048. ppv = (VOID**) &pvar->parray;
  2049. fPostAllocInit = TRUE;
  2050. break;
  2051. case VT_ARRAY | VT_I1:
  2052. case VT_ARRAY | VT_UI1:
  2053. cbskip = 0;
  2054. ppv = (VOID**) &pvar->parray;
  2055. cb = sizeof(BYTE);
  2056. break;
  2057. case VT_ARRAY | VT_I2:
  2058. case VT_ARRAY | VT_UI2:
  2059. case VT_ARRAY | VT_BOOL:
  2060. cbskip = 0;
  2061. ppv = (VOID**) &pvar->parray;
  2062. cb = sizeof(USHORT);
  2063. break;
  2064. case VT_ARRAY | VT_I4:
  2065. case VT_ARRAY | VT_UI4:
  2066. case VT_ARRAY | VT_INT:
  2067. case VT_ARRAY | VT_UINT:
  2068. case VT_ARRAY | VT_R4:
  2069. case VT_ARRAY | VT_ERROR:
  2070. cbskip = 0;
  2071. ppv = (VOID**) &pvar->parray;
  2072. cb = sizeof(ULONG);
  2073. break;
  2074. case VT_ARRAY | VT_DECIMAL:
  2075. cbskip = 0;
  2076. ppv = (VOID**) &pvar->parray;
  2077. cb = sizeof(DECIMAL);
  2078. break;
  2079. /*
  2080. case VT_ARRAY | VT_I8:
  2081. case VT_ARRAY | VT_UI8:
  2082. */
  2083. case VT_ARRAY | VT_DATE:
  2084. cbskip = 0;
  2085. ppv = (VOID**) &pvar->parray;
  2086. cb = sizeof(ULONGLONG);
  2087. // If byte swapping, swap as DWORDs
  2088. CBBYTESWAP(DWORD);
  2089. break;
  2090. case VT_ARRAY | VT_R8:
  2091. case VT_ARRAY | VT_CY:
  2092. cbskip = 0;
  2093. ppv = (VOID**) &pvar->parray;
  2094. cb = sizeof(CY);
  2095. // If byte swapping, swap as LONGLONGs
  2096. CBBYTESWAP(cb);
  2097. break;
  2098. default:
  2099. propDbg(( DEB_IWARN, "StgConvertPropertyToVariant: unsupported vt=%d\n", pvar->vt ));
  2100. *pstatus = STATUS_NOT_SUPPORTED;
  2101. goto Exit;
  2102. } // switch (pvar->vt)
  2103. // ------------------------------------------------------
  2104. // We've now analyzed the serialized property, learned
  2105. // about it, and loaded part or all of the PropVariant.
  2106. // Now we can load any remaining parts.
  2107. // ------------------------------------------------------
  2108. // Is this a simple, unaligned scalar?
  2109. if (pv != NULL)
  2110. {
  2111. // Yes. All we need to do is copy some bytes.
  2112. PROPASSERT(pchConvert == NULL);
  2113. PROPASSERT( cb < sizeof(PROPVARIANT)-sizeof(VARTYPE)
  2114. ||
  2115. VT_DECIMAL == pprop->dwType );
  2116. // Copy from the pprop into the PropVariant
  2117. RtlCopyMemory(pv, pprop->rgb, cb);
  2118. // We also might need to byte-swap them (but only in the PropVar).
  2119. PBSBuffer( pv, cb, cbByteSwap );
  2120. // Decimal requires special handling, since it overlaps the VT field.
  2121. if( VT_DECIMAL == PropByteSwap(pprop->dwType) )
  2122. pvar->vt = VT_DECIMAL;
  2123. } // if (pv != NULL)
  2124. // Otherwise, we need to allocate memory, to which the
  2125. // PropVariant will point.
  2126. else if (ppv != NULL)
  2127. {
  2128. *ppv = NULL;
  2129. // If cb is zero, then there's nothing to allocate anyway.
  2130. if( cb == 0 )
  2131. {
  2132. // Make sure it's legal for this type to be NULL.
  2133. if (!fNullLegal)
  2134. {
  2135. StatusInvalidParameter(pstatus, "StgConvertPropertyToVariant: bad NULL");
  2136. goto Exit;
  2137. }
  2138. }
  2139. else
  2140. {
  2141. // We need to allocate something.
  2142. SAFEARRAYBOUND *rgsaBounds = NULL;
  2143. ULONG cElems = 0, cbBounds = 0;
  2144. PROPASSERT(cb != 0);
  2145. // Allocate the necessary buffer (which we figured out in the
  2146. // switch above). For vector properties, this will just be the
  2147. // pElems buffer at this point. For singleton BSTR properties, we'll skip
  2148. // this allocate altogether; they're allocated by oleaut with SysStringAlloc.
  2149. // For array properties, we'll allocate the safearray and the buffer that
  2150. // it will reference.
  2151. if( VT_ARRAY & pvar->vt )
  2152. {
  2153. // This is a SafeArray. We need to use oleaut to allocate the SafeArray
  2154. // structure.
  2155. VARTYPE vtInternal; // The VT as determined by the SafeArray
  2156. UINT cDims = 0;
  2157. // Read the SafeArray's internal VT
  2158. // (PropertyLength guarantees us that we can read the VT,
  2159. // cDims, and bounds).
  2160. vtInternal = *(VARTYPE*) &pprop->rgb[cbskip];
  2161. cbskip += sizeof(ULONG);
  2162. // Read the dimension count
  2163. cDims = *(ULONG*) &pprop->rgb[cbskip];
  2164. cbskip += sizeof(DWORD);
  2165. // Point to the SAFEARRAYBOUND array
  2166. rgsaBounds = (SAFEARRAYBOUND*) &pprop->rgb[cbskip];
  2167. // We now have everything we need to create a new safe array
  2168. psa = PrivSafeArrayCreateEx( vtInternal, cDims, rgsaBounds, NULL );
  2169. if( NULL == psa )
  2170. {
  2171. propDbg(( DEB_ERROR, "Failed SafeArrayCreateEx, vt=0x%x, cDims=%d\n",
  2172. vtInternal, cDims ));
  2173. *pstatus = STATUS_NO_MEMORY;
  2174. goto Exit;
  2175. }
  2176. cbskip += cDims * sizeof(SAFEARRAYBOUND);
  2177. // Calculate the number of elements in the safearray.
  2178. PROPASSERT( cb == psa->cbElements );
  2179. *pstatus = SerializeSafeArrayBounds( psa, NULL, &cbBounds, &cElems );
  2180. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2181. // In the big switch above, cb was set to the single element size.
  2182. // Now update it to be the total element size.
  2183. cb *= cElems;
  2184. // Put this SafeArray into pvar->parray
  2185. *ppv = psa;
  2186. // Get the newly-created psa->pvData
  2187. *pstatus = PrivSafeArrayAccessData( psa, &pvSafeArrayData );
  2188. if( FAILED(*pstatus) ) goto Exit;
  2189. fSafeArrayLocked = TRUE;
  2190. // Point ppv to it - we'll copy the data from the serialized
  2191. // format to here.
  2192. ppv = &pvSafeArrayData;
  2193. PROPASSERT( NULL != ppv && psa != *ppv );
  2194. } // if( VT_ARRAY & pvar->vt )
  2195. else if( VT_BSTR != pvar->vt )
  2196. {
  2197. // Array was handled in the if above, BSTRs are handled below
  2198. // (simultaneous with the copy), so this else if block is for
  2199. // everything else - i.e. simple allocs.
  2200. *ppv = pma->Allocate(max(1, cb));
  2201. if (*ppv == NULL)
  2202. {
  2203. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory");
  2204. goto Exit;
  2205. }
  2206. } // if( VT_ARRAY & pvar->vt ) ... else if( VT_BSTR != pvar->vt )
  2207. // We've got memory allocated now.
  2208. // Can we load the PropVariant with a simple copy?
  2209. if( !fPostAllocInit )
  2210. {
  2211. // Yes - all we need is a memcopy (and an implicit alloc for BSTRs).
  2212. if (VT_BSTR == pvar->vt)
  2213. {
  2214. // We do the copy with the OleAutomation routine
  2215. // (which does an allocation too).
  2216. //
  2217. // If byte-swapping is necessary, the switch block
  2218. // already took care of it, leaving the buffer in
  2219. // 'pchConvert'.
  2220. //
  2221. // We already validated that the string is properly terminated.
  2222. // Now do the alloc/copy
  2223. PROPASSERT( NULL == *ppv );
  2224. *ppv = PrivSysAllocString( ( pchConvert != NULL )
  2225. ? (OLECHAR *) pchConvert
  2226. : (OLECHAR *) (pprop->rgb + cbskip) );
  2227. if (*ppv == NULL)
  2228. {
  2229. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory");
  2230. goto Exit;
  2231. }
  2232. } // if (VT_BSTR == pvar->vt)
  2233. else
  2234. {
  2235. // Copy the property into the PropVariant.
  2236. RtlCopyMemory(
  2237. *ppv,
  2238. pchConvert != NULL?
  2239. (BYTE const *) pchConvert : pprop->rgb + cbskip,
  2240. cb);
  2241. }
  2242. // If necessary, byte-swap the property (only in the PropVar).
  2243. PBSBuffer( *ppv, cb, cbByteSwap );
  2244. } // if (!fPostAllocInit)
  2245. else
  2246. {
  2247. // We must do more than just a simple copy.
  2248. // (Thus this is a vector/array of strings, variants, or CFs).
  2249. // Pointer to the correct location in pprop->rgb
  2250. BYTE const *pbsrc;
  2251. // Point pbsrc to the actual data (i.e. beyond the counts). For
  2252. // vectors, put the element count in cElems.
  2253. if( VT_VECTOR & pvar->vt )
  2254. {
  2255. // Get the element count
  2256. cElems = pvar->calpstr.cElems;
  2257. // Initialize the source pointer to point just beyond
  2258. // the element count.
  2259. pbsrc = pprop->rgb + sizeof(ULONG);
  2260. }
  2261. else
  2262. {
  2263. PROPASSERT( VT_ARRAY & pvar->vt );
  2264. PROPASSERT( 0 != cElems );
  2265. // Initialize the source pointer to point just beyond the VT, cDims, and bounds
  2266. pbsrc = pprop->rgb + cbBounds + sizeof(DWORD) + sizeof(UINT);
  2267. }
  2268. // Zero all pointers in the pElems array for easy caller cleanup
  2269. // (cb is the size of the array of pointers)
  2270. ppv = (VOID **) *ppv;
  2271. RtlZeroMemory(ppv, cb);
  2272. // Handle Variants, ClipFormats, & Strings separately.
  2273. if( (VT_VECTOR | VT_VARIANT) == pvar->vt
  2274. ||
  2275. (VT_ARRAY | VT_VARIANT) == pvar->vt )
  2276. {
  2277. // This is an array or vector of variants
  2278. PROPVARIANT *pvarT = (PROPVARIANT *) ppv;
  2279. PROPASSERT(!fIndirect);
  2280. // Loop through the variants.
  2281. while (cElems-- > 0)
  2282. {
  2283. ULONG cbelement;
  2284. // Get this variant into pvarT (which is really part of
  2285. // the pvar->capropvar->pElems).
  2286. fIndirect = StgConvertPropertyToVariantNoEH(
  2287. (SERIALIZEDPROPERTYVALUE const *) pbsrc,
  2288. cbprop - (ULONG)((UINT_PTR)pbsrc - (UINT_PTR)pprop),
  2289. CodePage,
  2290. pvarT,
  2291. pma,
  2292. pstatus);
  2293. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2294. PROPASSERT(!fIndirect);
  2295. // Calculate this size of this serialized element.
  2296. cbelement = PropertyLengthNoEH(
  2297. (SERIALIZEDPROPERTYVALUE const *) pbsrc,
  2298. cbprop - (ULONG)((UINT_PTR)pbsrc - (UINT_PTR)pprop),
  2299. CPSS_VARIANTVECTOR,
  2300. pstatus);
  2301. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2302. // Advance pbsrc by that size, and advance pvarT to the
  2303. // next element in pvar->capropvar->pElems.
  2304. pbsrc += cbelement;
  2305. pvarT++;
  2306. }
  2307. } // if (pvar->vt == (VT_VECTOR | VT_VARIANT) ... )
  2308. else if (pvar->vt == (VT_VECTOR | VT_CF))
  2309. {
  2310. // Handle vectors of clipformats.
  2311. // Set pcd to &pElems[0]
  2312. CLIPDATA *pcd = (CLIPDATA *) ppv;
  2313. // Loop through pElems
  2314. while (cElems-- > 0)
  2315. {
  2316. // What is the size of the clipdata (including sizeof(ulClipFmt))?
  2317. pcd->cbSize = PropByteSwap( ((CLIPDATA *) pbsrc)->cbSize );
  2318. if( pcd->cbSize < sizeof(pcd->ulClipFmt) )
  2319. {
  2320. StatusError(pstatus, "StgConvertPropertyToVariant: Invalid VT_CF cbSize",
  2321. STATUS_INTERNAL_DB_CORRUPTION);
  2322. goto Exit;
  2323. }
  2324. // How many bytes should we copy to pClipData?
  2325. cb = CBPCLIPDATA( *pcd );
  2326. // Set the ClipFormat & advance pbsrc to the clipdata.
  2327. pcd->ulClipFmt = PropByteSwap( ((CLIPDATA *) pbsrc)->ulClipFmt );
  2328. pbsrc += 2 * sizeof(ULONG);
  2329. // Copy the ClipData into the PropVariant
  2330. pcd->pClipData = NULL;
  2331. if (cb > 0)
  2332. {
  2333. // Get a buffer for the clip data.
  2334. pcd->pClipData = (BYTE *) pma->Allocate(cb);
  2335. if (pcd->pClipData == NULL)
  2336. {
  2337. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory for CF[]");
  2338. goto Exit;
  2339. }
  2340. // Copy the clipdata into pElems[i].pClipData
  2341. RtlCopyMemory(pcd->pClipData, pbsrc, cb);
  2342. ADJUSTPOINTER(pcd->pClipData, PointerDelta, BYTE *);
  2343. } // if (cb > 0)
  2344. // Move pcd to &pElems[i+1], and advance the buffer pointer.
  2345. pcd++;
  2346. pbsrc += DwordAlign(cb);
  2347. } // while (cElems-- > 0)
  2348. } // else if (pvar->vt == (VT_VECTOR | VT_CF))
  2349. else
  2350. {
  2351. // This is a vector or array of some kind of string.
  2352. // Assume that characters are CHARs
  2353. ULONG cbch = sizeof(char);
  2354. if( pvar->vt == (VT_VECTOR | VT_LPWSTR) )
  2355. {
  2356. // Characters are actually WCHARs
  2357. cbch = sizeof(WCHAR);
  2358. // If byte-swapping is enabled, LPWSTRs must have
  2359. // their WCHARs swapped.
  2360. CBBYTESWAP( sizeof(WCHAR) );
  2361. }
  2362. // Loop through the array
  2363. while (cElems-- > 0)
  2364. {
  2365. ULONG cbcopy;
  2366. // Read the cb from the front of the property, and advance
  2367. // pbsrc beyond that length field.
  2368. cbcopy = cb = PropByteSwap( *((ULONG *) pbsrc) ) * cbch;
  2369. pbsrc += sizeof(ULONG);
  2370. pv = (VOID *) pbsrc;
  2371. PROPASSERT(*ppv == NULL);
  2372. PROPASSERT(pchConvert == NULL);
  2373. // Do we have actual data to work with?
  2374. if( cb != 0 )
  2375. {
  2376. // Validate that the string is null terminated
  2377. if( CP_WINUNICODE == CodePage
  2378. //&& L'\0' != ((WCHAR*)pv)[ (cb-1) / sizeof(WCHAR) ]
  2379. && S_OK != StringCbLengthW((WCHAR*)pv, cb, NULL )
  2380. ||
  2381. CP_WINUNICODE != CodePage
  2382. //&& '\0' != ((CHAR*)pv)[ cb-1 ]
  2383. && S_OK != StringCbLengthA((CHAR*)pv, cb, NULL )
  2384. )
  2385. {
  2386. StatusError(pstatus, "String element missing null termination",
  2387. STATUS_INTERNAL_DB_CORRUPTION );
  2388. goto Exit;
  2389. }
  2390. // Special BSTR pre-processing ... it might be
  2391. // necessary to do a unicode/ansi conversion.
  2392. if( (VT_VECTOR | VT_BSTR) == pvar->vt
  2393. ||
  2394. (VT_ARRAY | VT_BSTR) == pvar->vt )
  2395. {
  2396. // If the propset & in-memory BSTRs are of
  2397. // different Unicode-ness, convert now.
  2398. if (CodePage != CP_WINUNICODE // Ansi PropSet
  2399. &&
  2400. OLECHAR_IS_UNICODE ) // Unicode BSTRs
  2401. {
  2402. PROPASSERT(IsAnsiString((CHAR*) pv, cb));
  2403. PrpConvertToUnicode(
  2404. (CHAR const *) pv,
  2405. cb,
  2406. CodePage,
  2407. (WCHAR **) &pchConvert,
  2408. &cbcopy,
  2409. pstatus);
  2410. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2411. pv = pchConvert;
  2412. }
  2413. else
  2414. if (CodePage == CP_WINUNICODE // Unicode PropSet
  2415. &&
  2416. !OLECHAR_IS_UNICODE ) // Ansi BSTRs
  2417. {
  2418. // If byte-swapping is necessary, the string from
  2419. // the propset must be swapped before it can be
  2420. // converted to MBCS. If such a conversion
  2421. // is necessary, a new buffer is alloced and
  2422. // put in pchByteSwap. Either way, 'pv' points
  2423. // to the correct string.
  2424. PBSInPlaceAlloc( (WCHAR**) &pv,
  2425. (WCHAR**) &pchByteSwap,
  2426. pstatus );
  2427. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2428. PROPASSERT(IsUnicodeString((WCHAR*)pv, cb));
  2429. // Convert the Unicode string from the property
  2430. // set to Ansi.
  2431. PrpConvertToMultiByte(
  2432. (WCHAR const *) pv,
  2433. cb,
  2434. CP_ACP, // Use the system default codepage
  2435. &pchConvert,
  2436. &cbcopy,
  2437. pstatus);
  2438. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2439. // 'pv' always has the correct string.
  2440. pv = pchConvert;
  2441. }
  2442. else
  2443. if (CodePage == CP_WINUNICODE)
  2444. {
  2445. // Both the BSTR is unicode in the property set,
  2446. // and must remain unicode in the PropVariant.
  2447. // But byte-swapping may still be necessary.
  2448. CBBYTESWAP( sizeof(WCHAR) );
  2449. }
  2450. #ifdef LITTLEENDIAN
  2451. PROPASSERT( IsOLECHARString((BSTR)pv, cbcopy ));
  2452. #endif
  2453. } // if( (VT_VECTOR | VT_BSTR) == pvar->vt ...
  2454. // Special LPSTR pre-processing ... again, we might
  2455. // need to do a unicode/ansi conversion.
  2456. else if (pvar->vt == (VT_VECTOR | VT_LPSTR))
  2457. {
  2458. // LPSTRs are always Ansi. If the string
  2459. // is Unicode in the propset, convert now.
  2460. if (CodePage == CP_WINUNICODE)
  2461. {
  2462. // If byte-swapping is necessary, the string from
  2463. // the propset must be swapped before it can be
  2464. // converted to MBCS. If such a conversion
  2465. // is necessary, a new buffer is alloced and
  2466. // put in pchByteSwap. Either way, 'pv' points
  2467. // to the correct string.
  2468. PBSInPlaceAlloc( (WCHAR**) &pv, (WCHAR**) &pchByteSwap,
  2469. pstatus );
  2470. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2471. PROPASSERT(IsUnicodeString((WCHAR*)pv, cb));
  2472. // Convert to Ansi.
  2473. PrpConvertToMultiByte(
  2474. (WCHAR const *) pv,
  2475. cb,
  2476. CP_ACP, // Use the system default codepage
  2477. &pchConvert,
  2478. &cbcopy,
  2479. pstatus);
  2480. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2481. pv = pchConvert;
  2482. }
  2483. PROPASSERT( IsAnsiString( (CHAR const *)pv, cbcopy ));
  2484. } // else if (pvar->vt == (VT_VECTOR | VT_LPSTR))
  2485. // Allocate memory in the PropVariant and copy
  2486. // the string.
  2487. if( (VT_BSTR | VT_VECTOR) == pvar->vt
  2488. ||
  2489. (VT_BSTR | VT_ARRAY) == pvar->vt )
  2490. {
  2491. // For BSTRs, the allocate/copy is performed
  2492. // by SysStringAlloc. We've already verified
  2493. // that the string pointed to by pv is properly
  2494. // terminated.
  2495. *ppv = PrivSysAllocString( (BSTR) pv );
  2496. if (*ppv == NULL)
  2497. {
  2498. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory for BSTR element");
  2499. goto Exit;
  2500. }
  2501. // The BSTR length should be the property length
  2502. // minus the NULL.
  2503. PROPASSERT( BSTRLEN(*ppv) == cbcopy - sizeof(OLECHAR) );
  2504. } // if( VT_BSTR == pvar->vt )
  2505. else
  2506. {
  2507. // For everything that's not a BSTR,
  2508. // Allocate a buffer in the PropVariant
  2509. *ppv = pma->Allocate(max(1, cbcopy));
  2510. if (*ppv == NULL)
  2511. {
  2512. StatusKBufferOverflow(pstatus, "StgConvertPropertyToVariant: no memory for string element");
  2513. goto Exit;
  2514. }
  2515. // And then copy from the propset buffer to the PropVariant
  2516. RtlCopyMemory(*ppv, pv, cbcopy);
  2517. } // if( VT_BSTR == pvar->vt ) ... else
  2518. // If necessary, byte-swap in the PropVariant to get
  2519. // the proper byte-ordering.
  2520. PBSBuffer( *ppv, cbcopy, cbByteSwap );
  2521. // Adjust the PropVar element ptr to user-space (kernel only)
  2522. ADJUSTPOINTER(*ppv, PointerDelta, VOID *);
  2523. // Move, within the propset buffer, to the
  2524. // next element in the vector.
  2525. pbsrc += DwordAlign(cb);
  2526. // Delete the temporary buffers
  2527. CoTaskMemFree( pchByteSwap );
  2528. pchByteSwap = NULL;
  2529. CoTaskMemFree( pchConvert );
  2530. pchConvert = NULL;
  2531. } // if (cb != 0)
  2532. // Move, within the PropVariant, to the next
  2533. // element in the vector.
  2534. ppv++;
  2535. } // while (cElems-- > 0)
  2536. } // else if (pvar->vt == (VT_VECTOR | VT_CF)) ... else
  2537. } // if (!fPostAllocInit) ... else
  2538. ADJUSTPOINTER(*ppvK, PointerDelta, VOID *);
  2539. } // if (cb == 0) ... else
  2540. } // if (pv != NULL) ... else if (ppv != NULL)
  2541. Exit:
  2542. if( fSafeArrayLocked )
  2543. {
  2544. PROPASSERT( NULL != pvSafeArrayData );
  2545. PrivSafeArrayUnaccessData( psa );
  2546. }
  2547. CoTaskMemFree( pchByteSwap );
  2548. CoTaskMemFree( pchConvert );
  2549. return(fIndirect);
  2550. }
  2551. //+---------------------------------------------------------------------------
  2552. // Function: CleanupVariants, private
  2553. //
  2554. // Synopsis: Free all memory used by an array of PROPVARIANT
  2555. //
  2556. // Arguments: [pvar] -- pointer to PROPVARIANT
  2557. // [cprop] -- property count
  2558. // [pma] -- caller's memory free routine
  2559. //
  2560. // Returns: None
  2561. //---------------------------------------------------------------------------
  2562. VOID
  2563. CleanupVariants(
  2564. IN PROPVARIANT *pvar,
  2565. IN ULONG cprop,
  2566. IN PMemoryAllocator *pma)
  2567. {
  2568. // We can get null if we're called recursively (for a vector),
  2569. // and the vector property never got fully set up (i.e. the
  2570. // second buffer never got allocated).
  2571. if( NULL == pvar )
  2572. return;
  2573. while (cprop-- > 0)
  2574. {
  2575. VOID *pv = NULL;
  2576. VOID **ppv = NULL;
  2577. ULONG cElems = 0;
  2578. switch (pvar->vt)
  2579. {
  2580. case VT_CF:
  2581. pv = pvar->pclipdata;
  2582. if (pv != NULL && pvar->pclipdata->pClipData)
  2583. {
  2584. pma->Free(pvar->pclipdata->pClipData);
  2585. }
  2586. break;
  2587. case VT_VERSIONED_STREAM:
  2588. pv = pvar->pVersionedStream;
  2589. if( NULL != pv && NULL != pvar->pVersionedStream->pStream )
  2590. {
  2591. pma->Free(pvar->pVersionedStream->pStream);
  2592. }
  2593. break;
  2594. case VT_BLOB:
  2595. case VT_BLOB_OBJECT:
  2596. pv = pvar->blob.pBlobData;
  2597. break;
  2598. case VT_BSTR:
  2599. case VT_CLSID:
  2600. case VT_STREAM:
  2601. case VT_STREAMED_OBJECT:
  2602. case VT_STORAGE:
  2603. case VT_STORED_OBJECT:
  2604. case VT_LPSTR:
  2605. case VT_LPWSTR:
  2606. AssertStringField(puuid); // VT_CLSID
  2607. AssertStringField(pszVal); // VT_STREAM, VT_STREAMED_OBJECT
  2608. AssertStringField(pszVal); // VT_STORAGE, VT_STORED_OBJECT
  2609. AssertStringField(bstrVal); // VT_BSTR
  2610. AssertStringField(pszVal); // VT_LPSTR
  2611. AssertStringField(pwszVal); // VT_LPWSTR
  2612. pv = pvar->pszVal;
  2613. break;
  2614. // Vector properties:
  2615. case VT_VECTOR | VT_I1:
  2616. case VT_VECTOR | VT_UI1:
  2617. case VT_VECTOR | VT_I2:
  2618. case VT_VECTOR | VT_UI2:
  2619. case VT_VECTOR | VT_BOOL:
  2620. case VT_VECTOR | VT_I4:
  2621. case VT_VECTOR | VT_UI4:
  2622. case VT_VECTOR | VT_R4:
  2623. case VT_VECTOR | VT_ERROR:
  2624. case VT_VECTOR | VT_I8:
  2625. case VT_VECTOR | VT_UI8:
  2626. case VT_VECTOR | VT_R8:
  2627. case VT_VECTOR | VT_CY:
  2628. case VT_VECTOR | VT_DATE:
  2629. case VT_VECTOR | VT_FILETIME:
  2630. case VT_VECTOR | VT_CLSID:
  2631. AssertByteVector(cac); // VT_I1
  2632. AssertByteVector(caub); // VT_UI1
  2633. AssertShortVector(cai); // VT_I2
  2634. AssertShortVector(caui); // VT_UI2
  2635. AssertShortVector(cabool); // VT_BOOL
  2636. AssertLongVector(cal); // VT_I4
  2637. AssertLongVector(caul); // VT_UI4
  2638. AssertLongVector(caflt); // VT_R4
  2639. AssertLongVector(cascode); // VT_ERROR
  2640. AssertLongLongVector(cah); // VT_I8
  2641. AssertLongLongVector(cauh); // VT_UI8
  2642. AssertLongLongVector(cadbl); // VT_R8
  2643. AssertLongLongVector(cacy); // VT_CY
  2644. AssertLongLongVector(cadate); // VT_DATE
  2645. AssertLongLongVector(cafiletime); // VT_FILETIME
  2646. AssertVarVector(cauuid, sizeof(GUID)); // VT_CLSID
  2647. pv = pvar->cai.pElems;
  2648. break;
  2649. case VT_VECTOR | VT_CF:
  2650. {
  2651. CLIPDATA *pcd;
  2652. cElems = pvar->caclipdata.cElems;
  2653. pv = pcd = pvar->caclipdata.pElems;
  2654. while (cElems-- > 0)
  2655. {
  2656. if (pcd->pClipData != NULL)
  2657. {
  2658. pma->Free(pcd->pClipData);
  2659. }
  2660. pcd++;
  2661. }
  2662. }
  2663. break;
  2664. case VT_VECTOR | VT_BSTR:
  2665. case VT_VECTOR | VT_LPSTR:
  2666. case VT_VECTOR | VT_LPWSTR:
  2667. AssertStringVector(cabstr); // VT_BSTR
  2668. AssertStringVector(calpstr); // VT_LPSTR
  2669. AssertStringVector(calpwstr); // VT_LPWSTR
  2670. cElems = pvar->calpstr.cElems;
  2671. ppv = (VOID **) pvar->calpstr.pElems;
  2672. break;
  2673. case VT_VECTOR | VT_VARIANT:
  2674. CleanupVariants(
  2675. pvar->capropvar.pElems,
  2676. pvar->capropvar.cElems,
  2677. pma);
  2678. pv = pvar->capropvar.pElems;
  2679. break;
  2680. } // switch (pvar->vt)
  2681. if (ppv != NULL) // STRING VECTOR property
  2682. {
  2683. // Save the vector of pointers
  2684. pv = (VOID *) ppv;
  2685. // Free the vector elements
  2686. while (cElems-- > 0)
  2687. {
  2688. if (*ppv != NULL)
  2689. {
  2690. if( (VT_BSTR | VT_VECTOR) == pvar->vt )
  2691. {
  2692. PrivSysFreeString( (BSTR) *ppv );
  2693. }
  2694. else
  2695. {
  2696. pma->Free((BYTE *) *ppv);
  2697. }
  2698. }
  2699. ppv++;
  2700. }
  2701. // Free the vector of pointers.
  2702. pma->Free(pv);
  2703. pv = NULL;
  2704. } // if (ppv != NULL)
  2705. if (pv != NULL)
  2706. {
  2707. if( VT_BSTR == pvar->vt )
  2708. {
  2709. PrivSysFreeString( (BSTR) pv );
  2710. }
  2711. else
  2712. {
  2713. pma->Free((BYTE *) pv);
  2714. }
  2715. }
  2716. pvar->vt = VT_EMPTY;
  2717. // Move on to the next PropVar in the vector.
  2718. pvar++;
  2719. } // while (cprop-- > 0)
  2720. }
  2721. //+--------------------------------------------------------------------------
  2722. // Function: PropertyLength
  2723. //
  2724. // Synopsis: compute the length of a property including the variant type
  2725. //
  2726. // Arguments: [pprop] -- property value
  2727. // [cbbuf] -- max length of accessible memory at pprop
  2728. // [flags] -- CPropertySetStream flags
  2729. // [pstatus] -- pointer to NTSTATUS code
  2730. //
  2731. // Returns: length of property
  2732. //---------------------------------------------------------------------------
  2733. // First, define a wrapper for this function which returns errors
  2734. // using NT Exception Handling, rather than returning an NTSTATUS.
  2735. #if defined(WINNT) && !defined(IPROPERTY_DLL)
  2736. ULONG
  2737. PropertyLength(
  2738. SERIALIZEDPROPERTYVALUE const *pprop,
  2739. ULONG cbbuf,
  2740. BYTE flags)
  2741. {
  2742. NTSTATUS status;
  2743. ULONG ulRet;
  2744. ulRet = PropertyLengthNoEH( pprop, cbbuf, flags, &status );
  2745. if (!NT_SUCCESS( status ))
  2746. RtlRaiseStatus( status );
  2747. return( ulRet );
  2748. }
  2749. #endif // #if defined(WINNT) && !defined(IPROPERTY_DLL)
  2750. // Now define the body of the function, returning errors with an
  2751. // NTSTATUS value instead of raising.
  2752. ULONG
  2753. PropertyLengthNoEH(
  2754. SERIALIZEDPROPERTYVALUE const *pprop,
  2755. ULONG cbbuf,
  2756. BYTE flags,
  2757. OUT NTSTATUS *pstatus)
  2758. {
  2759. ULONG const *pl = (ULONG const *) pprop->rgb;
  2760. ULONG cElems = 1;
  2761. ULONG cSafeArrayDimensions = 1;
  2762. ULONG cbremain = cbbuf;
  2763. ULONG cb = 0, cbch;
  2764. BOOLEAN fIllegalType = FALSE;
  2765. const SAFEARRAYBOUND *rgsaBounds = NULL;
  2766. ULONG vt;
  2767. *pstatus = STATUS_SUCCESS;
  2768. // Can we read the VT?
  2769. if (cbremain < CB_SERIALIZEDPROPERTYVALUE)
  2770. {
  2771. StatusOverflow(pstatus, "PropertyLength: dwType");
  2772. goto Exit;
  2773. }
  2774. // Get the VT
  2775. vt = PropByteSwap( pprop->dwType );
  2776. cbremain -= CB_SERIALIZEDPROPERTYVALUE;
  2777. PROPASSERT( sizeof(pprop->dwType) == CB_SERIALIZEDPROPERTYVALUE );
  2778. // If this is a vector or array, get the element count
  2779. if( VT_VECTOR & vt )
  2780. {
  2781. // It's a vector.
  2782. // Can we read the element count?
  2783. if (cbremain < sizeof(ULONG))
  2784. {
  2785. StatusOverflow(pstatus, "PropertyLength: cElems");
  2786. goto Exit;
  2787. }
  2788. // Get the element count
  2789. cElems = PropByteSwap( *pl++ );
  2790. cbremain -= sizeof(ULONG);
  2791. }
  2792. else if( VT_ARRAY & vt )
  2793. {
  2794. // It's an array
  2795. ULONG cbBounds = 0;
  2796. // Can we read the element VT and dimension count?
  2797. // (This VT is for the members of the array, as opposed
  2798. // to the VT_ARRAY in pprop->dwType).
  2799. if( sizeof(DWORD) + sizeof(UINT) > cbremain )
  2800. {
  2801. StatusOverflow(pstatus, "PropertyLength: vt/cDims" );
  2802. goto Exit;
  2803. }
  2804. // Read the SafeArray's VT (so we'll now ignore pprop->dwType)
  2805. vt = VT_ARRAY | PropByteSwap( *pl++ );
  2806. PROPASSERT( sizeof(DWORD) == sizeof(*pl) );
  2807. // Read the dimension count
  2808. cSafeArrayDimensions = PropByteSwap( *pl++ );
  2809. PROPASSERT( sizeof(DWORD) == sizeof(*pl) );
  2810. // Update the remaining count to be the bytes after the vt/count
  2811. cbremain -= sizeof(DWORD) + sizeof(UINT);
  2812. // Can we read the bounds?
  2813. cbBounds = sizeof(SAFEARRAYBOUND) * cSafeArrayDimensions;
  2814. if( cbBounds > cbremain )
  2815. {
  2816. StatusOverflow(pstatus, "PropertyLength: safearray bounds" );
  2817. goto Exit;
  2818. }
  2819. // Get the bounds (point to them directly in the pprop)
  2820. cbremain -= cbBounds;
  2821. rgsaBounds = reinterpret_cast<const SAFEARRAYBOUND *>(pl);
  2822. pl = static_cast<const ULONG*>(Add2ConstPtr( pl, cbBounds ));
  2823. // Finally, calc the element count
  2824. cElems = CalcSafeArrayElements( cSafeArrayDimensions, rgsaBounds );
  2825. }
  2826. // Is this a vector/array of variants? If so, we need to make recursive
  2827. // calls to size the elements.
  2828. if( (VT_VECTOR | VT_VARIANT) == vt
  2829. ||
  2830. (VT_ARRAY | VT_VARIANT) == vt )
  2831. {
  2832. while (cElems-- > 0)
  2833. {
  2834. cb = PropertyLengthNoEH(
  2835. (SERIALIZEDPROPERTYVALUE const *) pl,
  2836. cbremain,
  2837. flags | CPSS_VARIANTVECTOR,
  2838. pstatus);
  2839. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  2840. pl = (ULONG const *) Add2ConstPtr(pl, cb);
  2841. cbremain -= cb;
  2842. }
  2843. }
  2844. // Otherwise (it's not a vector/array), we have to look at each
  2845. // type individually.
  2846. else
  2847. {
  2848. // Assume that characters are Unicode
  2849. // (we'll update this if it's not true).
  2850. cbch = sizeof(WCHAR);
  2851. // Switch over the raw type (i.e., mask out vt_vector, vt_array, etc.)
  2852. // We won't see VT_VARIANT here because we handled it in the if above.
  2853. // If we're in a recursive call, CPSS_VARIANTVECTOR will be true, and
  2854. // consequently certain types will be illegal (such as VT_NULL - you can't
  2855. // have this type in a vector|variant). Mostly, this switch updates
  2856. // pl to point just beyond the data - the total size in the end will be
  2857. // the delta between this and pprop. Note that we don't actually try
  2858. // to dereference pl, because it may be pointing off the end of the buffer
  2859. // (i.e., we don't check cbremain during the switch).
  2860. switch( VT_TYPEMASK & vt )
  2861. {
  2862. case VT_EMPTY:
  2863. case VT_NULL:
  2864. fIllegalType = (flags & CPSS_VARIANTVECTOR) != 0;
  2865. break;
  2866. case VT_I1:
  2867. case VT_UI1:
  2868. pl = (ULONG const *) Add2ConstPtr(pl, DwordAlign(cElems * sizeof(BYTE)));
  2869. break;
  2870. case VT_I2:
  2871. case VT_UI2:
  2872. case VT_BOOL:
  2873. pl = (ULONG const *) Add2ConstPtr(pl, DwordAlign(cElems * sizeof(USHORT)));
  2874. break;
  2875. case VT_I4:
  2876. case VT_INT:
  2877. case VT_UI4:
  2878. case VT_UINT:
  2879. case VT_R4:
  2880. case VT_ERROR:
  2881. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(ULONG));
  2882. break;
  2883. case VT_I8:
  2884. case VT_UI8:
  2885. case VT_R8:
  2886. case VT_CY:
  2887. case VT_DATE:
  2888. case VT_FILETIME:
  2889. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(LONGLONG));
  2890. break;
  2891. case VT_CLSID:
  2892. pl = (ULONG const *) Add2ConstPtr(pl, cElems * sizeof(GUID));
  2893. break;
  2894. case VT_DECIMAL:
  2895. pl = (ULONG const *) Add2ConstPtr( pl, cElems * sizeof(DECIMAL) );
  2896. break;
  2897. case VT_VERSIONED_STREAM:
  2898. // Ensure we can read the GUID & string length
  2899. if( cbremain < sizeof(GUID) + sizeof(ULONG) )
  2900. {
  2901. StatusOverflow(pstatus, "PropertyLength: VersionedStream" );
  2902. goto Exit;
  2903. }
  2904. // Point to the string's length
  2905. pl = reinterpret_cast<const ULONG*>( Add2ConstPtr( pl, sizeof(GUID) ));
  2906. // Point past the end of the property
  2907. pl = reinterpret_cast<const ULONG*>( Add2ConstPtr( pl, sizeof(ULONG) + DwordAlign(PropByteSwap(*pl)) ));
  2908. break;
  2909. case VT_BLOB:
  2910. case VT_BLOB_OBJECT:
  2911. // FALLTHROUGH
  2912. case VT_STREAM:
  2913. case VT_STREAMED_OBJECT:
  2914. case VT_STORAGE:
  2915. case VT_STORED_OBJECT:
  2916. // These are stored as strings (which are the name of a
  2917. // stream/storage).
  2918. if (flags & CPSS_VARIANTVECTOR)
  2919. {
  2920. fIllegalType = TRUE;
  2921. break;
  2922. }
  2923. // FALLTHROUGH
  2924. case VT_CF:
  2925. case VT_BSTR:
  2926. case VT_LPSTR:
  2927. // This have byte counts, not character counts
  2928. cbch = sizeof(BYTE);
  2929. // FALLTHROUGH
  2930. case VT_LPWSTR:
  2931. // Handle all the length-prefixed types
  2932. while (cElems-- > 0)
  2933. {
  2934. if (cbremain < sizeof(ULONG) ||
  2935. cbremain < (cb = sizeof(ULONG) + DwordAlign(PropByteSwap(*pl) * cbch)))
  2936. {
  2937. StatusOverflow(pstatus, "PropertyLength: String/BLOB/CF/Indirect");
  2938. goto Exit;
  2939. }
  2940. #ifdef LITTLEENDIAN
  2941. PROPASSERT(
  2942. (PropByteSwap(pprop->dwType) & VT_TYPEMASK) != VT_LPWSTR
  2943. ||
  2944. IsUnicodeString( (WCHAR const *) &pl[1],
  2945. PropByteSwap(*pl) * sizeof(WCHAR)));
  2946. #endif
  2947. pl = (ULONG const *) Add2ConstPtr(pl, cb);
  2948. cbremain -= cb;
  2949. }
  2950. break;
  2951. default:
  2952. fIllegalType = TRUE;
  2953. break;
  2954. } // switch( VT_TYPEMASK & vt )
  2955. }
  2956. // Did we get an illegal type (e.g. a VT_STREAM within a CPSS_VARIANTVECTOR)?
  2957. if (fIllegalType)
  2958. {
  2959. propDbg(( DEB_IWARN, "PropertyLength: Unsupported VarType (0x%x)\n", vt ));
  2960. *pstatus = STATUS_NOT_SUPPORTED;
  2961. goto Exit;
  2962. }
  2963. // Calculate the final cb and verify it.
  2964. cb = (ULONG) ((BYTE *) pl - (BYTE *) pprop);
  2965. if (cbbuf < cb)
  2966. {
  2967. StatusOverflow(pstatus, "PropertyLength: cb");
  2968. goto Exit;
  2969. }
  2970. // Make sure PropertyLength works when limited to an exact size buffer.
  2971. PROPASSERT(cb == cbbuf || PropertyLengthNoEH(pprop, cb, flags, pstatus) == cb);
  2972. // ----
  2973. // Exit
  2974. // ----
  2975. Exit:
  2976. // Normalize the error return value.
  2977. if( !NT_SUCCESS(*pstatus) )
  2978. cb = 0;
  2979. return(cb);
  2980. } // PropertyLengthNoEH()
  2981. //+--------------------------------------------------------------------------
  2982. // Function: StgPropertyLengthAsVariant
  2983. //
  2984. // Synopsis: compute the size of external memory required to store the
  2985. // property as a PROPVARIANT
  2986. //
  2987. // Arguments: [pprop] -- property value
  2988. // [cbprop] -- computed length of pprop in propset stream
  2989. // [CodePage] -- property set codepage
  2990. // [flags] -- CPropertySetStream flags
  2991. // [pstatus] -- pointer to NTSTATUS code
  2992. //
  2993. // Returns: length of property
  2994. //---------------------------------------------------------------------------
  2995. #if defined(WINNT)
  2996. // First, define a wrapper which raises NT Exceptions for compatibility
  2997. // with older callers who expect it.
  2998. EXTERN_C ULONG __stdcall
  2999. StgPropertyLengthAsVariant(
  3000. IN SERIALIZEDPROPERTYVALUE const *pprop,
  3001. IN ULONG cbprop,
  3002. IN USHORT CodePage,
  3003. IN BYTE flags)
  3004. {
  3005. NTSTATUS status;
  3006. ULONG ulRet;
  3007. ulRet = StgPropertyLengthAsVariantNoEH( pprop, cbprop, CodePage, flags, &status );
  3008. if (!NT_SUCCESS( status ))
  3009. RtlRaiseStatus( status );
  3010. return( ulRet );
  3011. }
  3012. // Now define the body of the function, returning errors with an
  3013. // NTSTATUS value instead of raising.
  3014. ULONG
  3015. StgPropertyLengthAsVariantNoEH(
  3016. IN SERIALIZEDPROPERTYVALUE const *pprop,
  3017. IN ULONG cbprop,
  3018. IN USHORT CodePage,
  3019. IN BYTE flags,
  3020. OUT NTSTATUS *pstatus)
  3021. {
  3022. ULONG cElems = 0;
  3023. ULONG cbvar = 0;
  3024. const ULONG *pl = reinterpret_cast<const ULONG*>(pprop->rgb);
  3025. *pstatus = STATUS_SUCCESS;
  3026. PROPASSERT(cbprop == PropertyLengthNoEH(pprop, cbprop, flags, pstatus));
  3027. if( VT_VECTOR & PropByteSwap(pprop->dwType) )
  3028. {
  3029. if( VT_ARRAY & PropByteSwap(pprop->dwType) )
  3030. {
  3031. StatusInvalidParameter( pstatus, "Both Array and Vector bits set" );
  3032. goto Exit;
  3033. }
  3034. cElems = *(ULONG *) pprop->rgb;
  3035. pl++;
  3036. cbprop -= sizeof(ULONG); // Discount the element count
  3037. }
  3038. else if( VT_ARRAY & PropByteSwap(pprop->dwType) )
  3039. {
  3040. const SAFEARRAYBOUND *rgsaBounds = NULL;
  3041. ULONG cDims = 0;
  3042. VARTYPE vtInternal;
  3043. if( VT_VECTOR & PropByteSwap(pprop->dwType) )
  3044. {
  3045. StatusInvalidParameter( pstatus, "Both Array and Vector bits set" );
  3046. goto Exit;
  3047. }
  3048. vtInternal = static_cast<VARTYPE>(*pl++);
  3049. cDims = *pl++; PROPASSERT( sizeof(UINT) == sizeof(LONG) );
  3050. rgsaBounds = reinterpret_cast<const SAFEARRAYBOUND*>(pl);
  3051. pl = static_cast<const ULONG*>( Add2ConstPtr( pl, cDims * sizeof(SAFEARRAYBOUND) ));
  3052. cElems = CalcSafeArrayElements( cDims, rgsaBounds );
  3053. // Adjust cbprop to take into account that we have to create a SafeArray
  3054. cbprop = cbprop
  3055. - sizeof(DWORD) // vtInternal
  3056. - sizeof(UINT) // cDims
  3057. + sizeof(SAFEARRAY) // The SafeArray that will be alloced
  3058. + sizeof(GUID) // hidden extra data alloc-ed with a safearray
  3059. - sizeof(SAFEARRAYBOUND); // Discount SAFEARRAY.rgsabound[1]
  3060. }
  3061. switch( PropByteSwap(pprop->dwType) )
  3062. {
  3063. // We don't need to check for VT_BYREF, becuase serialized property sets
  3064. // never contain them.
  3065. //default:
  3066. //case VT_EMPTY:
  3067. //case VT_NULL:
  3068. //case VT_I1:
  3069. //case VT_UI1:
  3070. //case VT_I2:
  3071. //case VT_UI2:
  3072. //case VT_BOOL:
  3073. //case VT_INT:
  3074. //case VT_UINT:
  3075. //case VT_I4:
  3076. //case VT_UI4:
  3077. //case VT_R4:
  3078. //case VT_ERROR:
  3079. //case VT_I8:
  3080. //case VT_UI8:
  3081. //case VT_R8:
  3082. //case VT_CY:
  3083. //case VT_DATE:
  3084. //case VT_FILETIME:
  3085. //case VT_DECIMAL:
  3086. //cbvar = 0;
  3087. //break;
  3088. case VT_CLSID:
  3089. cbvar = cbprop - sizeof(ULONG); // don't include VARTYPE
  3090. break;
  3091. // VT_CF: Round CLIPDATA up to Quad boundary, then drop VARTYPE+size+
  3092. // clipfmt, which get tossed or unmarshalled into CLIPDATA. Round
  3093. // byte-granular data size to a Quad boundary when returning result.
  3094. case VT_CF:
  3095. cbvar = QuadAlign(sizeof(CLIPDATA)) + cbprop - 3 * sizeof(ULONG);
  3096. break;
  3097. case VT_BLOB:
  3098. case VT_BLOB_OBJECT:
  3099. cbvar = cbprop - 2 * sizeof(ULONG); // don't include VARTYPE & size
  3100. break;
  3101. case VT_VERSIONED_STREAM:
  3102. case VT_STREAM:
  3103. case VT_STREAMED_OBJECT:
  3104. case VT_STORAGE:
  3105. case VT_STORED_OBJECT:
  3106. cbvar = cbprop - 2 * sizeof(ULONG); // don't include VARTYPE & size
  3107. if (CodePage != CP_WINUNICODE)
  3108. {
  3109. cbvar *= sizeof(WCHAR); // worst case Unicode conversion
  3110. }
  3111. break;
  3112. case VT_BSTR:
  3113. // Don't include the size of the VT field, but leave
  3114. // the size of the length field accounted for.
  3115. cbvar = cbprop - sizeof(ULONG);
  3116. // Worst-case Ansi->Unicode conversion:
  3117. cbvar *= sizeof(OLECHAR);
  3118. break;
  3119. case VT_LPSTR: // Assume Ansi conversion saves no space
  3120. case VT_LPWSTR:
  3121. cbvar = cbprop - 2 * sizeof(ULONG);
  3122. break;
  3123. case VT_ARRAY | VT_I1:
  3124. case VT_ARRAY | VT_UI1:
  3125. case VT_ARRAY | VT_I2:
  3126. case VT_ARRAY | VT_UI2:
  3127. case VT_ARRAY | VT_BOOL:
  3128. case VT_ARRAY | VT_I4:
  3129. case VT_ARRAY | VT_UI4:
  3130. case VT_ARRAY | VT_INT:
  3131. case VT_ARRAY | VT_UINT:
  3132. case VT_ARRAY | VT_R4:
  3133. case VT_ARRAY | VT_ERROR:
  3134. case VT_ARRAY | VT_DECIMAL:
  3135. //case VT_ARRAY | VT_I8:
  3136. //case VT_ARRAY | VT_UI8:
  3137. case VT_ARRAY | VT_R8:
  3138. case VT_ARRAY | VT_CY:
  3139. case VT_ARRAY | VT_DATE:
  3140. // don't include VARTYPE field
  3141. cbvar = cbprop - sizeof(ULONG);
  3142. break;
  3143. // Vector properties:
  3144. case VT_VECTOR | VT_I1:
  3145. case VT_VECTOR | VT_UI1:
  3146. case VT_VECTOR | VT_I2:
  3147. case VT_VECTOR | VT_UI2:
  3148. case VT_VECTOR | VT_BOOL:
  3149. case VT_VECTOR | VT_I4:
  3150. case VT_VECTOR | VT_UI4:
  3151. case VT_VECTOR | VT_R4:
  3152. case VT_VECTOR | VT_ERROR:
  3153. case VT_VECTOR | VT_I8:
  3154. case VT_VECTOR | VT_UI8:
  3155. case VT_VECTOR | VT_R8:
  3156. case VT_VECTOR | VT_CY:
  3157. case VT_VECTOR | VT_DATE:
  3158. case VT_VECTOR | VT_FILETIME:
  3159. case VT_VECTOR | VT_CLSID:
  3160. AssertByteVector(cac); // VT_I1
  3161. AssertByteVector(caub); // VT_UI1
  3162. AssertShortVector(cai); // VT_I2
  3163. AssertShortVector(caui); // VT_UI2
  3164. AssertShortVector(cabool); // VT_BOOL
  3165. AssertLongVector(cal); // VT_I4
  3166. AssertLongVector(caul); // VT_UI4
  3167. AssertLongVector(caflt); // VT_R4
  3168. AssertLongVector(cascode); // VT_ERROR
  3169. AssertLongLongVector(cah); // VT_I8
  3170. AssertLongLongVector(cauh); // VT_UI8
  3171. AssertLongLongVector(cadbl); // VT_R8
  3172. AssertLongLongVector(cacy); // VT_CY
  3173. AssertLongLongVector(cadate); // VT_DATE
  3174. AssertLongLongVector(cafiletime); // VT_FILETIME
  3175. AssertVarVector(cauuid, sizeof(GUID));
  3176. // don't include VARTYPE and count fields
  3177. cbvar = cbprop - 2 * sizeof(ULONG);
  3178. break;
  3179. case VT_VECTOR | VT_CF: // add room for each pointer
  3180. AssertVarVector(caclipdata, sizeof(CLIPDATA)); // VT_CF
  3181. // don't include VARTYPE and count fields
  3182. cbvar = cbprop - 2 * sizeof(ULONG);
  3183. // add room for each CLIPDATA data pointer and enough to Quad align
  3184. // every clipdata data element and 1 ULONG to Quad align the
  3185. // CLIPDATA array
  3186. cbvar += cElems * (sizeof(BYTE *) + sizeof(ULONG)) + sizeof(ULONG);
  3187. break;
  3188. case VT_VECTOR | VT_BSTR: // add room for each BSTRLEN
  3189. case VT_ARRAY | VT_BSTR:
  3190. AssertStringVector(cabstr); // VT_BSTR
  3191. //Assert
  3192. // don't include VARTYPE field
  3193. cbvar = cbprop - sizeof(ULONG);
  3194. // For vectors, don't include the count field
  3195. if( VT_VECTOR & PropByteSwap(pprop->dwType) )
  3196. cbvar -= sizeof(ULONG);
  3197. if (CodePage != CP_WINUNICODE)
  3198. {
  3199. cbvar *= sizeof(OLECHAR); // worst case Unicode conversion
  3200. }
  3201. // add room for each BSTRLEN value and enough to Quad align
  3202. // every BSTR and 1 ULONG to Quad align the array of BSTR pointers.
  3203. cbvar += cElems * (sizeof(ULONG) + sizeof(ULONG)) + sizeof(ULONG);
  3204. break;
  3205. case VT_VECTOR | VT_LPSTR: // Assume Ansi conversion saves no space
  3206. case VT_VECTOR | VT_LPWSTR:
  3207. AssertStringVector(calpstr); // VT_LPSTR
  3208. AssertStringVector(calpwstr); // VT_LPWSTR
  3209. // don't include VARTYPE and count fields
  3210. cbvar = cbprop - 2 * sizeof(ULONG);
  3211. // add enough room to Quadalign the array of string pointers.
  3212. cbvar += cElems * sizeof(ULONG) + sizeof(ULONG);
  3213. break;
  3214. case VT_VECTOR | VT_VARIANT:
  3215. case VT_ARRAY | VT_VARIANT:
  3216. {
  3217. ULONG cbremain = cbprop - sizeof(ULONG); // Discount the VT
  3218. cbvar = cElems * sizeof(PROPVARIANT);
  3219. while (cElems-- > 0)
  3220. {
  3221. ULONG cbpropElem;
  3222. ULONG cbvarElem;
  3223. cbpropElem = PropertyLengthNoEH(
  3224. (SERIALIZEDPROPERTYVALUE *) pl,
  3225. cbremain,
  3226. flags | CPSS_VARIANTVECTOR,
  3227. pstatus);
  3228. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  3229. cbvarElem = StgPropertyLengthAsVariantNoEH(
  3230. (SERIALIZEDPROPERTYVALUE *) pl,
  3231. cbpropElem,
  3232. CodePage,
  3233. flags | CPSS_VARIANTVECTOR,
  3234. pstatus);
  3235. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  3236. pl = (ULONG const *) Add2ConstPtr(pl, cbpropElem);
  3237. cbremain -= cbpropElem;
  3238. cbvar += cbvarElem;
  3239. }
  3240. break;
  3241. }
  3242. }
  3243. // ----
  3244. // Exit
  3245. // ----
  3246. Exit:
  3247. // Normalize the error return value.
  3248. if( !NT_SUCCESS(*pstatus) )
  3249. cbvar = 0;
  3250. return(QuadAlign(cbvar));
  3251. } // StgPropertyLengthAsVariantNoEH
  3252. #endif // #if defined(WINNT)
  3253. //+--------------------------------------------------------------------------
  3254. // Function: PBSCopy
  3255. //
  3256. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  3257. // only compile in the BIGENDIAN build. In the
  3258. // LITTLEENDIAN build, they are inlined with NOOP functions.
  3259. //
  3260. // This routine copies the source to the destination,
  3261. // byte-swapping as it copies.
  3262. //
  3263. // Arguments: [VOID*] pvDest
  3264. // Pointer to the target (swapped) buffer.
  3265. // This must be pre-allocated by the caller.
  3266. // [VOID*] pvSource
  3267. // Pointer to the original buffer.
  3268. // [ULONG] cbSize
  3269. // Size in bytes of the buffer.
  3270. // [ULONG] cbByteSwap
  3271. // Size of byte-swapping units.
  3272. //
  3273. // Returns: None.
  3274. //
  3275. //---------------------------------------------------------------------------
  3276. #ifdef BIGENDIAN
  3277. VOID PBSCopy( OUT VOID *pvDest,
  3278. IN VOID const *pvSource,
  3279. IN ULONG cbCopy,
  3280. IN LONG cbByteSwap )
  3281. {
  3282. PROPASSERT( (cbCopy & 1) == 0 );
  3283. PROPASSERT( pvDest != NULL && pvSource != NULL );
  3284. memcpy( pvDest, pvSource, cbCopy );
  3285. PBSBuffer( pvDest, cbCopy, cbByteSwap );
  3286. }
  3287. #endif // BIGENDIAN
  3288. //+--------------------------------------------------------------------------
  3289. // Function: PBSAllocAndCopy
  3290. //
  3291. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  3292. // only compile in the BIGENDIAN build. In the
  3293. // LITTLEENDIAN build, they are inlined with NOOP functions.
  3294. //
  3295. // This routine allocs a buffer, and swaps the bytes from
  3296. // the source buffer into the destination.
  3297. //
  3298. // Arguments: [VOID**] ppvDest (out)
  3299. // On success will point to the swapped buffer.
  3300. // [VOID*] pvSource (in)
  3301. // Pointer to the original buffer.
  3302. // [ULONG] cbSize (in)
  3303. // Size in bytes of the buffer.
  3304. // [LONG] cbByteSwap (in)
  3305. // Size of byte-swapping units.
  3306. // [NTSTATUS*] pstatus (out)
  3307. // NTSTATUS code.
  3308. //
  3309. // Returns: None.
  3310. //
  3311. // Note: The caller is responsible for freeing *ppvDest
  3312. // (using ::delete).
  3313. //
  3314. //---------------------------------------------------------------------------
  3315. #ifdef BIGENDIAN
  3316. VOID PBSAllocAndCopy( OUT VOID **ppvDest,
  3317. IN VOID const *pvSource,
  3318. ULONG cbSize,
  3319. LONG cbByteSwap,
  3320. OUT NTSTATUS *pstatus)
  3321. {
  3322. // -----
  3323. // Begin
  3324. // -----
  3325. *pstatus = STATUS_SUCCESS;
  3326. PROPASSERT( ppvDest != NULL && pvSource != NULL );
  3327. // Allocate a buffer.
  3328. *ppvDest = CoTaskMemAlloc( cbSize );
  3329. if( NULL == *ppvDest )
  3330. {
  3331. *pstatus = STATUS_NO_MEMORY;
  3332. goto Exit;
  3333. }
  3334. // Swap/copy the bytes.
  3335. PBSCopy( *ppvDest, pvSource, cbSize, cbByteSwap );
  3336. // ----
  3337. // Exit
  3338. // ----
  3339. Exit:
  3340. return;
  3341. } // PBSAllocAndCopy
  3342. #endif // BIGENDIAN
  3343. //+--------------------------------------------------------------------------
  3344. // Function: PBSInPlaceAlloc
  3345. //
  3346. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  3347. // only compile in the BIGENDIAN build. In the
  3348. // LITTLEENDIAN build, they are inlined with NOOP functions.
  3349. //
  3350. // This routine takes a WCHAR array, allocates a new buffer,
  3351. // and swaps the original array into the new buffer.
  3352. //
  3353. //
  3354. // Arguments: [WCHAR**] ppwszResult
  3355. // IN: *ppwszResult points to string to be swapped.
  3356. // OUT: *ppwszResult points to the swapped string.
  3357. // [WCHAR**] ppwszBuffer
  3358. // *ppwszBuffer points to the buffer which was allocated
  3359. // for the swapped bytes (should be the same as *ppwszResult).
  3360. // *ppwszBuffer must be NULL on input, and must be freed
  3361. // by the caller (using ::delete).
  3362. // [NTSTATUS*] pstatus
  3363. // NTSTATUS code.
  3364. //
  3365. // Returns: None.
  3366. //
  3367. // On input, *ppwszResult contains the original string.
  3368. // An equivalently sized buffer is allocated in *ppwszBuffer,
  3369. // and *ppwszResult is byte-swapped into it. *ppwszResult
  3370. // is then set to the new *ppwszBuffer.
  3371. //
  3372. // It doesn't appear to useful to have both buffer parameters,
  3373. // but it makes it easier on the caller in certain circumstances;
  3374. // *ppwszResult always points to the correct string, whether the
  3375. // build is BIGENDIAN (alloc & swap takes place) or the build
  3376. // is LITTLEENDIAN (nothing happes, so *ppwszResult continues
  3377. // to point to the proper string). The LITTLEENDIAN version of
  3378. // this function is implemented as an inline routine.
  3379. //
  3380. //---------------------------------------------------------------------------
  3381. #ifdef BIGENDIAN
  3382. VOID PBSInPlaceAlloc( IN OUT WCHAR** ppwszResult,
  3383. OUT WCHAR** ppwszBuffer,
  3384. OUT NTSTATUS *pstatus )
  3385. {
  3386. // ------
  3387. // Locals
  3388. // ------
  3389. WCHAR *pwszNewBuffer;
  3390. // Pointers which will walk through the input buffers.
  3391. WCHAR *pwszOriginal, *pwszSwapped;
  3392. // -----
  3393. // Begin
  3394. // -----
  3395. *pstatus = STATUS_SUCCESS;
  3396. // Allocate a new buffer.
  3397. pwszNewBuffer = CoTaskMemAlloc( sizeof(WCHAR)*( Prop_wcslen(*ppwszResult) + 1 ));
  3398. if( NULL == pwszNewBuffer )
  3399. {
  3400. *pstatus = STATUS_NO_MEMORY;
  3401. goto Exit;
  3402. }
  3403. // Swap the WCHARs into the new buffer.
  3404. pwszOriginal = *ppwszResult;
  3405. pwszSwapped = pwszNewBuffer;
  3406. do
  3407. {
  3408. *pwszSwapped = PropByteSwap(*pwszOriginal++);
  3409. } while( *pwszSwapped++ != L'\0' );
  3410. // If the caller wants a special pointer to the new buffer,
  3411. // set it now.
  3412. if( NULL != ppwszBuffer )
  3413. {
  3414. PROPASSERT( NULL== *ppwszBuffer );
  3415. *ppwszBuffer = pwszNewBuffer;
  3416. }
  3417. // Also point *ppwszResult to the new buffer.
  3418. *ppwszResult = pwszNewBuffer;
  3419. // ----
  3420. // Exit
  3421. // ----
  3422. Exit:
  3423. return;
  3424. } // PropByteSwap( WCHAR**, WCHAR**, NTSTATUS*)
  3425. #endif // BIGENDIAN
  3426. //+--------------------------------------------------------------------------
  3427. // Function: PBSBuffer
  3428. //
  3429. // Synopsis: This is a Property Byte-Swap routine. The PBS routines
  3430. // only compile in the BIGENDIAN build. In the
  3431. // LITTLEENDIAN build, they are inlined with NOOP functions.
  3432. //
  3433. // This routine takes a buffer and byte-swaps it. The caller
  3434. // specifies the size of the buffer, and the granularity of
  3435. // the byte-swapping.
  3436. //
  3437. // Arguments: [VOID*] pv
  3438. // Pointer to the buffer to be swapped.
  3439. // [ULONG] cbSize
  3440. // Size in bytes of the buffer.
  3441. // [ULONG] cbByteSwap
  3442. // Size of byte-swapping units.
  3443. //
  3444. // Returns: None.
  3445. //
  3446. // For example, an array of 4 WORDs could be swapped with:
  3447. //
  3448. // PBSBuffer( (VOID*) aw, 8, sizeof(WORD) );
  3449. //
  3450. //---------------------------------------------------------------------------
  3451. #ifdef BIGENDIAN
  3452. VOID PBSBuffer( IN OUT VOID *pv,
  3453. IN ULONG cbSize,
  3454. IN ULONG cbByteSwap )
  3455. {
  3456. ULONG ulIndex;
  3457. // What kind of swapping should be do?
  3458. switch( cbByteSwap )
  3459. {
  3460. // No swapping required
  3461. case 0:
  3462. case( sizeof(BYTE) ):
  3463. // Nothing to do.
  3464. break;
  3465. // Swap WORDs
  3466. case( sizeof(WORD) ):
  3467. for( ulIndex = 0; ulIndex < cbSize/sizeof(WORD); ulIndex++ )
  3468. ByteSwap( &((WORD*)pv)[ulIndex] );
  3469. break;
  3470. // Swap DWORDs
  3471. case( sizeof(DWORD) ):
  3472. for( ulIndex = 0; ulIndex < cbSize/sizeof(DWORD); ulIndex++ )
  3473. ByteSwap( &((DWORD*)pv)[ulIndex] );
  3474. break;
  3475. // Swap LONGLONGs
  3476. case( sizeof(LONGLONG) ):
  3477. for( ulIndex = 0; ulIndex < cbSize/sizeof(LONGLONG); ulIndex++ )
  3478. ByteSwap( &((LONGLONG*)pv)[ulIndex] );
  3479. break;
  3480. // Swap GUIDs
  3481. case CBBYTESWAP_UID:
  3482. for( ulIndex = 0; ulIndex < cbSize/sizeof(GUID); ulIndex++ )
  3483. ByteSwap( &((GUID*)pv)[ulIndex] );
  3484. break;
  3485. // Error
  3486. default:
  3487. PROPASSERT( !"Invalid generic byte-swap size" );
  3488. }
  3489. } // PropByteSwap( VOID*, ULONG, ULONG )
  3490. #endif // BIGENDIAN