Source code of Windows XP (NT5)
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.

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