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.

1017 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 2000
  5. //
  6. // File: PropRec.cxx
  7. //
  8. // Contents: Record format for persistent property store
  9. //
  10. // Classes: CPropertyRecord
  11. //
  12. // History: 28-Dec-19 KyleP Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <stgvar.hxx>
  18. #include <propvar.h>
  19. #include <propstm.hxx>
  20. #include <proprec.hxx>
  21. #include <eventlog.hxx>
  22. #include <pmalloc.hxx>
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Member: COnDiskPropertyRecord::ReadFixed, public
  26. //
  27. // Synopsis: Read fixed-length property
  28. //
  29. // Arguments: [Ordinal] -- Ordinal of property to locate.
  30. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  31. // [oStart] -- Offset to start of specific fixed property.
  32. // [cTotal] -- Total number of properties in record.
  33. // [Type] -- Data type of value
  34. // [var] -- Value returned here.
  35. // [pbExtra] -- Indirect data stored here
  36. // [pcbExtra] -- On input, size of [pbExtra]. On output,
  37. // amount used.
  38. //
  39. // History: 27-Dec-95 KyleP Created.
  40. //
  41. //----------------------------------------------------------------------------
  42. void COnDiskPropertyRecord::ReadFixed( ULONG Ordinal,
  43. ULONG Mask,
  44. ULONG oStart,
  45. ULONG cTotal,
  46. ULONG Type,
  47. PROPVARIANT & var,
  48. BYTE * pbExtra,
  49. unsigned * pcbExtra,
  50. PStorage & storage )
  51. {
  52. if ( !IsStored( Ordinal, Mask ) )
  53. {
  54. var.vt = VT_EMPTY;
  55. *pcbExtra = 0;
  56. }
  57. else
  58. {
  59. var.vt = (USHORT)Type;
  60. //
  61. // Start is after existance bitmap
  62. //
  63. ULONG const * pulStart = 0;
  64. if (IsLeanRecord())
  65. pulStart = &((SLeanRecord *)&Data)->_aul[ (cTotal-1) / 16 + 1 + oStart];
  66. else
  67. pulStart = &((SNormalRecord *)&Data)->_aul[ (cTotal-1) / 16 + 1 + oStart];
  68. switch ( Type )
  69. {
  70. case VT_I1:
  71. case VT_UI1:
  72. var.bVal = *(BYTE *)pulStart;
  73. *pcbExtra = 0;
  74. break;
  75. case VT_I2:
  76. case VT_UI2:
  77. case VT_BOOL:
  78. var.uiVal = *(USHORT *)pulStart;
  79. *pcbExtra = 0;
  80. break;
  81. case VT_I4:
  82. case VT_UI4:
  83. case VT_R4:
  84. case VT_ERROR:
  85. var.ulVal = *pulStart;
  86. *pcbExtra = 0;
  87. break;
  88. case VT_I8:
  89. case VT_UI8:
  90. case VT_R8:
  91. case VT_CY:
  92. case VT_DATE:
  93. case VT_FILETIME:
  94. RtlCopyMemory( &var.hVal, pulStart, sizeof(var.hVal) );
  95. *pcbExtra = 0;
  96. break;
  97. case VT_CLSID:
  98. if ( *pcbExtra < sizeof(CLSID) )
  99. {
  100. *pcbExtra = sizeof(CLSID);
  101. return;
  102. }
  103. if ( *pcbExtra == 0xFFFFFFFF )
  104. {
  105. var.puuid = (CLSID *)CoTaskMemAlloc( sizeof(CLSID) );
  106. if ( 0 == var.puuid )
  107. THROW( CException( E_OUTOFMEMORY ) );
  108. }
  109. else
  110. {
  111. *pcbExtra = sizeof(CLSID);
  112. var.puuid = (CLSID *)pbExtra;
  113. }
  114. RtlCopyMemory( var.puuid, pulStart, sizeof(CLSID) );
  115. break;
  116. default:
  117. ciDebugOut(( DEB_ERROR, "PROPSTORE: Reading invalid fixed type %d.\n", Type ));
  118. Win4Assert( !"Corrupt property store" );
  119. storage.ReportCorruptComponent( L"PropertyRecord1" );
  120. THROW( CException( CI_CORRUPT_CATALOG ) );
  121. break;
  122. }
  123. }
  124. }
  125. //+---------------------------------------------------------------------------
  126. //
  127. // Member: COnDiskPropertyRecord::ReadVariable, public
  128. //
  129. // Synopsis: Read variable-length property
  130. //
  131. // Arguments: [Ordinal] -- Ordinal of property to locate.
  132. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  133. // [oStart] -- Offset to start of variable storage area.
  134. // [cTotal] -- Total number of properties in record.
  135. // [cFixed] -- Count of fixed length properties
  136. // [var] -- Value returned here.
  137. // [pbExtra] -- Indirect data stored here
  138. // [pcbExtra] -- On input, size of [pbExtra]. On output,
  139. // amount used.
  140. //
  141. // Returns: FALSE if value must be stored in overflow record.
  142. //
  143. // History: 27-Dec-95 KyleP Created.
  144. // 14-Mar-2000 KLam Check results of memory allocation
  145. //
  146. //----------------------------------------------------------------------------
  147. BOOL COnDiskPropertyRecord::ReadVariable( ULONG Ordinal,
  148. ULONG Mask,
  149. ULONG oStart,
  150. ULONG cTotal,
  151. ULONG cFixed,
  152. PROPVARIANT & var,
  153. BYTE * pbExtra,
  154. unsigned * pcbExtra )
  155. {
  156. if ( !IsStored( Ordinal, Mask ) )
  157. {
  158. var.vt = VT_EMPTY;
  159. *pcbExtra = 0;
  160. }
  161. else
  162. {
  163. //
  164. // Check for overflow.
  165. //
  166. if ( IsStoredOnOverflow( Ordinal, Mask ) )
  167. return FALSE;
  168. //
  169. // Start is after existance bitmap and fixed properties.
  170. //
  171. ULONG * pulStart = FindVariableProp( Ordinal, cFixed, cTotal, oStart );
  172. Win4Assert( !IsOverflow( *pulStart ) );
  173. //
  174. // Compute the length of the property.
  175. //
  176. ULONG cbProp = UsedSize( *pulStart ) * 4;
  177. pulStart++; // Skip size field.
  178. ciDebugOut(( DEB_PROPSTORE,
  179. "Reading variable prop, ordinal %d at offset 0x%x (%d) in record. Size = %d bytes.\n",
  180. Ordinal,
  181. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this),
  182. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this),
  183. cbProp ));
  184. ULONG cb;
  185. BOOL fUnicodeSpecial = IsUnicodeSpecial( (SERIALIZEDPROPERTYVALUE *)pulStart,
  186. cb );
  187. if ( !fUnicodeSpecial )
  188. cb = StgPropertyLengthAsVariant( (SERIALIZEDPROPERTYVALUE *)pulStart,
  189. cbProp,
  190. CP_WINUNICODE,
  191. 0 );
  192. if ( cb <= *pcbExtra )
  193. {
  194. if ( *pcbExtra == 0xFFFFFFFF )
  195. {
  196. //
  197. // Unmarshall the property. Use the OLE allocator for extra mem
  198. //
  199. if ( fUnicodeSpecial )
  200. {
  201. ReadUnicodeSpecialCTMA( (SERIALIZEDPROPERTYVALUE *)pulStart,
  202. var );
  203. }
  204. else
  205. {
  206. CCoTaskMemAllocator BufferMgr;
  207. StgConvertPropertyToVariant( (SERIALIZEDPROPERTYVALUE *)pulStart,
  208. CP_WINUNICODE,
  209. &var,
  210. &BufferMgr );
  211. }
  212. #if CIDBG==1
  213. if ( (var.vt&0x0fff) > VT_CLSID )
  214. {
  215. ciDebugOut(( DEB_ERROR, "Bad Variant Type 0x%X\n", var.vt ));
  216. Win4Assert( !"Call KyleP" );
  217. }
  218. #endif // CIDBG==1
  219. }
  220. else
  221. {
  222. //
  223. // Unmarshall the property into a buffer.
  224. //
  225. if ( fUnicodeSpecial )
  226. {
  227. ReadUnicodeSpecial( (SERIALIZEDPROPERTYVALUE *)pulStart,
  228. var,
  229. pbExtra );
  230. }
  231. else
  232. {
  233. CNonAlignAllocator BufferMgr( *pcbExtra, pbExtra );
  234. StgConvertPropertyToVariant( (SERIALIZEDPROPERTYVALUE *)pulStart,
  235. CP_WINUNICODE,
  236. &var,
  237. &BufferMgr );
  238. // StgConverPropertyToVariant uses SafeArrayCreateEx for
  239. // VT_ARRAY allocation, even when an allocator is passed in!
  240. if ((var.vt & VT_ARRAY) == VT_ARRAY)
  241. {
  242. ciDebugOut(( DEB_ERROR, "Array Variant Type 0x%X\n", var.vt ));
  243. Win4Assert(BufferMgr.GetFreeSize() == *pcbExtra);
  244. SAFEARRAY * pSaSrc = var.parray;
  245. SAFEARRAY * pSaDest = 0;
  246. if ( SaCreateAndCopy( BufferMgr, pSaSrc, &pSaDest ) &&
  247. SaCreateDataUsingMA( BufferMgr,
  248. var.vt & ~VT_ARRAY,
  249. *pSaSrc,
  250. *pSaDest,
  251. TRUE ) )
  252. {
  253. SafeArrayDestroy(var.parray);
  254. var.parray = pSaDest;
  255. }
  256. else
  257. {
  258. Win4Assert( !"SafeArray copy failed!" );
  259. }
  260. }
  261. else if ((var.vt & ~(VT_VECTOR|VT_ARRAY)) == VT_BSTR)
  262. {
  263. //
  264. // StgConverPropertyToVariant uses SysAllocString for
  265. // BSTR allocation, even when an allocator is passed in!
  266. //
  267. unsigned cbBstr;
  268. switch ( var.vt )
  269. {
  270. case VT_BSTR:
  271. {
  272. Win4Assert(BufferMgr.GetFreeSize() == *pcbExtra);
  273. cbBstr = BSTRLEN( var.bstrVal ) + sizeof(OLECHAR) + sizeof(DWORD);
  274. BSTR bstr = (BSTR) BufferMgr.Allocate(cbBstr);
  275. if ( 0 == bstr )
  276. {
  277. THROW ( CException ( E_OUTOFMEMORY ) );
  278. }
  279. RtlCopyMemory( bstr, &BSTRLEN(var.bstrVal), cbBstr );
  280. SysFreeString( var.bstrVal );
  281. var.bstrVal = (BSTR) (((DWORD *)bstr) + 1);
  282. break;
  283. }
  284. case VT_BSTR|VT_VECTOR:
  285. {
  286. //
  287. // The vector pointer storage is allocated
  288. // using our allocator, but the bstrs are
  289. // allocated using SysAllocString.
  290. //
  291. for ( unsigned i = 0; i < var.cabstr.cElems; i++ )
  292. {
  293. cbBstr = BSTRLEN( var.cabstr.pElems[i] ) +
  294. sizeof(OLECHAR) + sizeof (DWORD);
  295. BSTR bstr = (BSTR) BufferMgr.Allocate(cbBstr);
  296. if ( 0 == bstr )
  297. {
  298. THROW ( CException ( E_OUTOFMEMORY ) );
  299. }
  300. RtlCopyMemory( bstr,
  301. &BSTRLEN(var.cabstr.pElems[i]),
  302. cbBstr);
  303. SysFreeString(var.cabstr.pElems[i]);
  304. var.cabstr.pElems[i] = (BSTR) (((DWORD *) bstr) + 1);
  305. }
  306. break;
  307. }
  308. }
  309. }
  310. else if (var.vt == (VT_VECTOR|VT_VARIANT))
  311. {
  312. ciDebugOut(( DEB_ERROR, "ReadVariable - Variant Vector Type\n" ));
  313. }
  314. }
  315. #if CIDBG==1
  316. if ( (var.vt&0x0fff) > VT_CLSID )
  317. {
  318. ciDebugOut(( DEB_ERROR, "Bad Variant Type 0x%X\n", var.vt ));
  319. Win4Assert( !"Call KyleP" );
  320. }
  321. #endif // CIDBG==1
  322. }
  323. }
  324. *pcbExtra = cb;
  325. }
  326. return TRUE;
  327. }
  328. //+---------------------------------------------------------------------------
  329. //
  330. // Member: COnDiskPropertyRecord::WriteFixed, public
  331. //
  332. // Synopsis: Write fixed-length property
  333. //
  334. // Arguments: [Ordinal] -- Ordinal of property to locate.
  335. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  336. // [oStart] -- Offset to start of specific property.
  337. // [Type] -- Expected data type (for type checking)
  338. // [cTotal] -- Total number of properties in record.
  339. // [var] -- Value to store.
  340. //
  341. // History: 27-Dec-95 KyleP Created.
  342. //
  343. //----------------------------------------------------------------------------
  344. void COnDiskPropertyRecord::WriteFixed( ULONG Ordinal,
  345. ULONG Mask,
  346. ULONG oStart,
  347. ULONG Type,
  348. ULONG cTotal,
  349. CStorageVariant const & var )
  350. {
  351. if ( var.Type() != (VARENUM)Type )
  352. {
  353. # if CIDBG == 1
  354. if ( var.Type() != VT_EMPTY )
  355. ciDebugOut(( DEB_WARN, "Type mismatch (%d vs. %d) writing fixed property\n",
  356. var.Type(), Type ));
  357. # endif
  358. ClearStored( Ordinal, Mask );
  359. return;
  360. }
  361. //
  362. // Start is after existance bitmap
  363. //
  364. ULONG * pulStart = 0;
  365. if (IsLeanRecord())
  366. pulStart = &((SLeanRecord *)&Data)->_aul[ (cTotal-1) / 16 + 1 + oStart];
  367. else
  368. pulStart = &((SNormalRecord *)&Data)->_aul[ (cTotal-1) / 16 + 1 + oStart];
  369. ciDebugOut(( DEB_PROPSTORE,
  370. "Writing fixed prop, ordinal %d (type %d) at offset 0x%x (%d) in record.\n",
  371. Ordinal,
  372. var.Type(),
  373. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this),
  374. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this) ));
  375. switch ( var.Type() )
  376. {
  377. case VT_I1:
  378. case VT_UI1:
  379. {
  380. ULONG ul = var.GetUI1();
  381. *pulStart = ul;
  382. }
  383. break;
  384. case VT_I2:
  385. case VT_UI2:
  386. case VT_BOOL:
  387. {
  388. ULONG ul = var.GetUI2();
  389. *pulStart = ul;
  390. }
  391. break;
  392. case VT_I4:
  393. case VT_UI4:
  394. case VT_R4:
  395. case VT_ERROR:
  396. *pulStart = var.GetUI4();
  397. break;
  398. case VT_I8:
  399. case VT_UI8:
  400. case VT_R8:
  401. case VT_CY:
  402. case VT_DATE:
  403. case VT_FILETIME:
  404. {
  405. ULARGE_INTEGER uli = var.GetUI8();
  406. RtlCopyMemory( pulStart, &uli, sizeof(uli) );
  407. }
  408. break;
  409. case VT_CLSID:
  410. RtlCopyMemory( pulStart, var.GetCLSID(), sizeof(CLSID) );
  411. break;
  412. default:
  413. Win4Assert( !"How did I get here?" );
  414. ClearStored( Ordinal, Mask );
  415. break;
  416. }
  417. SetStored( Ordinal, Mask );
  418. }
  419. //+---------------------------------------------------------------------------
  420. //
  421. // Member: COnDiskPropertyRecord::WriteVariable, public
  422. //
  423. // Synopsis: Write variable-length property
  424. //
  425. // Arguments: [Ordinal] -- Ordinal of property to locate.
  426. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  427. // [oStart] -- Offset to start of variable length area.
  428. // [cTotal] -- Total number of properties in record.
  429. // [cFixed] -- Count of fixed length properties
  430. // [culRec] -- Size (in dwords) of record
  431. // [var] -- Value to store.
  432. //
  433. // Returns: FALSE if record must be stored in overflow record.
  434. //
  435. // History: 27-Dec-95 KyleP Created.
  436. //
  437. //----------------------------------------------------------------------------
  438. BOOL COnDiskPropertyRecord::WriteVariable( ULONG Ordinal,
  439. ULONG Mask,
  440. ULONG oStart,
  441. ULONG cTotal,
  442. ULONG cFixed,
  443. ULONG culRec,
  444. CStorageVariant const & var,
  445. PStorage & storage )
  446. {
  447. Win4Assert(!IsLeanRecord());
  448. ULONG * pulStart = FindVariableProp( Ordinal, cFixed, cTotal, oStart );
  449. //
  450. // Are we freeing this property?
  451. //
  452. if ( var.Type() == VT_EMPTY )
  453. {
  454. ClearStored( Ordinal, Mask );
  455. ClearStoredOnOverflow( Ordinal, Mask );
  456. //
  457. // Overflow case: We need to fake the overflow to clean up linked records.
  458. //
  459. if ( IsOverflow( *pulStart ) )
  460. {
  461. SetUsedSize( pulStart, 0 );
  462. return FALSE;
  463. }
  464. else
  465. {
  466. //
  467. // Adjust size field, and total variable space for record.
  468. //
  469. Win4Assert( VariableUsed() >= UsedSize( *pulStart ) );
  470. SetVariableUsed(VariableUsed() - UsedSize( *pulStart ));
  471. SetUsedSize( pulStart, 0 );
  472. return TRUE;
  473. }
  474. }
  475. //
  476. // No matter what happens, we want to indicate the property was stored.
  477. //
  478. SetStored( Ordinal, Mask );
  479. ClearStoredOnOverflow( Ordinal, Mask );
  480. //
  481. // Compute the length of the property.
  482. //
  483. ULONG cul = 0;
  484. BOOL fUnicodeSpecial = IsUnicodeSpecial( var, cul );
  485. if ( !fUnicodeSpecial )
  486. {
  487. StgConvertVariantToProperty( (PROPVARIANT *)(ULONG_PTR)&var,
  488. CP_WINUNICODE,
  489. 0,
  490. &cul,
  491. pidInvalid,
  492. FALSE,
  493. 0 );
  494. Win4Assert( cul > 0 );
  495. cul = (cul - 1) / sizeof(ULONG) + 1;
  496. }
  497. ULONG culPrevUsed = UsedSize( *pulStart );
  498. //
  499. // Do we fit?
  500. //
  501. if ( cul > AllocatedSize( *pulStart ) )
  502. {
  503. //
  504. // Can we fit?
  505. //
  506. if ( cul >
  507. UsedSize( *pulStart ) + FreeVariableSpace( cTotal, cFixed, oStart, culRec ) )
  508. {
  509. ciDebugOut(( DEB_PROPSTORE, "Need overflow buffer for ordinal %u\n", Ordinal ));
  510. //
  511. // If we had a previous value, adjust total variable space for record.
  512. //
  513. if ( !IsOverflow( *pulStart ) )
  514. {
  515. Win4Assert( VariableUsed() >= UsedSize( *pulStart ) );
  516. SetVariableUsed(VariableUsed() - UsedSize( *pulStart ));
  517. }
  518. MarkOverflow( pulStart );
  519. SetStoredOnOverflow( Ordinal, Mask );
  520. return FALSE;
  521. }
  522. //
  523. // Need to move properties, but there *is* room in record for the shift.
  524. //
  525. //
  526. // First, compress previous properties.
  527. //
  528. #if CIDBG
  529. ULONG * pulOldStart = pulStart;
  530. #endif
  531. pulStart = LeftCompress( FindVariableProp( cFixed, cFixed, cTotal, oStart ),
  532. 0,
  533. pulStart );
  534. ciDebugOut(( DEB_PROPSTORE,
  535. "Freeing up %d bytes for variable prop %d via left compression\n",
  536. (pulOldStart - pulStart) * 4,
  537. Ordinal ));
  538. //
  539. // Then, if needed, push additional properties farther out.
  540. //
  541. if ( cul > AllocatedSize( *pulStart ) )
  542. {
  543. ULONG * pulNext = pulStart + AllocatedSize(*pulStart) + 1;
  544. ULONG culDelta = cul - AllocatedSize(*pulStart);
  545. ciDebugOut(( DEB_PROPSTORE,
  546. "Freeing up %d bytes for variable prop %d, starting at offset 0x%x (%d) via right compression\n",
  547. culDelta * 4,
  548. Ordinal,
  549. (ULONG)((ULONG_PTR)pulNext - (ULONG_PTR)this),
  550. (ULONG)((ULONG_PTR)pulNext - (ULONG_PTR)this) ));
  551. Win4Assert( Ordinal < cTotal );
  552. RightCompress( pulNext, // Next property
  553. culDelta, // Amount to shift
  554. cTotal - Ordinal - 1 ); // # props left in record
  555. SetAllocatedSize( pulStart, cul );
  556. }
  557. Win4Assert( cul <= AllocatedSize( *pulStart ) );
  558. }
  559. //
  560. // Adjust size field, and total variable space for record.
  561. //
  562. SetVariableUsed(VariableUsed() + cul - culPrevUsed);
  563. SetUsedSize( pulStart, cul );
  564. pulStart++; // Skip size field
  565. Win4Assert( AllocatedSize( *(pulStart - 1)) >= UsedSize( *(pulStart - 1) ) );
  566. ciDebugOut(( DEB_PROPSTORE,
  567. "Writing variable prop, ordinal %d at offset 0x%x (%d) in record. Size = %d bytes.\n",
  568. Ordinal,
  569. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this),
  570. (ULONG)((ULONG_PTR)pulStart - (ULONG_PTR)this),
  571. UsedSize(*(pulStart - 1)) * 4 ));
  572. if ( fUnicodeSpecial )
  573. {
  574. WriteUnicodeSpecial( var, (SERIALIZEDPROPERTYVALUE *)pulStart );
  575. }
  576. else
  577. {
  578. cul *= 4;
  579. if ( 0 == StgConvertVariantToProperty( (PROPVARIANT *)(ULONG_PTR)&var,
  580. CP_WINUNICODE,
  581. (SERIALIZEDPROPERTYVALUE *)pulStart,
  582. &cul,
  583. pidInvalid,
  584. FALSE,
  585. 0 ) )
  586. {
  587. ciDebugOut(( DEB_ERROR, "Error marshalling property!\n" ));
  588. Win4Assert( !"Corrupt property store" );
  589. storage.ReportCorruptComponent( L"PropertyRecord2" );
  590. THROW( CException( CI_CORRUPT_CATALOG ) );
  591. }
  592. }
  593. return TRUE;
  594. }
  595. //+---------------------------------------------------------------------------
  596. //
  597. // Member: COnDiskPropertyRecord::CountNormalRecordsToStore, public
  598. //
  599. // Synopsis: Compute size of value
  600. //
  601. // Arguments: [cTotal] -- Total number of properties in record.
  602. // [culRec] -- Size (in dwords) of record
  603. // [var] -- Value to store.
  604. //
  605. // Returns: Size in records needed to store property.
  606. //
  607. // History: 27-Dec-95 KyleP Created.
  608. //
  609. //----------------------------------------------------------------------------
  610. ULONG COnDiskPropertyRecord::CountNormalRecordsToStore( ULONG cTotal,
  611. ULONG culRec,
  612. CStorageVariant const & var )
  613. {
  614. //
  615. // Compute the length of the property.
  616. //
  617. ULONG cul = 0;
  618. BOOL fUnicodeSpecial = IsUnicodeSpecial( var, cul );
  619. if ( !fUnicodeSpecial )
  620. {
  621. StgConvertVariantToProperty( (PROPVARIANT *)(ULONG_PTR)&var,
  622. CP_WINUNICODE,
  623. 0,
  624. &cul,
  625. pidInvalid,
  626. FALSE,
  627. 0 );
  628. Win4Assert( cul > 0 );
  629. cul = (cul - 1) / sizeof(ULONG) + 1;
  630. }
  631. //
  632. // Add on the fixed overhead. We are computing cul to determine the number
  633. // of records to use as a single overflow record. Since we will end up with
  634. // a record of length >= culRec, we are assured that the overflow record has
  635. // enough space for free list mgmt. Hence we don't need to account for space
  636. // required for free list mgmt when computing cul.
  637. //
  638. cul += MinimalOverheadNormal() + // Minimal overhead for normal records
  639. (cTotal - 1) / 16 + 1 + // Existence bitmap
  640. cTotal; // Used/Alloc sizes
  641. return (cul - 1) / culRec + 1;
  642. }
  643. //+---------------------------------------------------------------------------
  644. //
  645. // Member: COnDiskPropertyRecord::RightCompress, public
  646. //
  647. // Synopsis: Moves data from [pul], [cul] dwords up.
  648. //
  649. // Arguments: [pul] -- Start of area to move.
  650. // [cul] -- Count of dwords to move
  651. // [cRemaining] -- Count of values remaining in buffer. Needed
  652. // because it is impossible to distinguish
  653. // used/alloc blocks from empty space.
  654. //
  655. // History: 27-Dec-95 KyleP Created.
  656. //
  657. //----------------------------------------------------------------------------
  658. void COnDiskPropertyRecord::RightCompress( ULONG * pul, ULONG cul, ULONG cRemaining )
  659. {
  660. //
  661. // Termination condition for recursion: We've scanned all variable
  662. // properties in this record. Any remaining space in record is
  663. // guaranteed to be free.
  664. //
  665. if ( 0 == cRemaining )
  666. return;
  667. ULONG FreeSpace = AllocatedSize(*pul) - UsedSize(*pul);
  668. if ( FreeSpace >= cul )
  669. {
  670. SetAllocatedSize( pul, AllocatedSize(*pul) - cul );
  671. }
  672. else
  673. {
  674. RightCompress( pul + AllocatedSize(*pul) + 1, cul - FreeSpace, cRemaining - 1 );
  675. SetAllocatedSize( pul, UsedSize(*pul) );
  676. }
  677. RtlMoveMemory( pul + cul, pul, (UsedSize(*pul) + 1) * 4 );
  678. }
  679. //+---------------------------------------------------------------------------
  680. //
  681. // Member: COnDiskPropertyRecord::LeftCompress, public
  682. //
  683. // Synopsis: Moves data from [pul], [cul] dwords down.
  684. //
  685. // Arguments: [pul] -- Start of area to move.
  686. // [cul] -- Count of dwords to move
  687. // [pulEnd] -- Terminating property. This property will have
  688. // it's allocated size increased with all the slack
  689. // from previous properties and have its used size
  690. // set to 0.
  691. //
  692. // Returns: New pointer to pulEnd (which moved down by [cul] bytes).
  693. //
  694. // History: 27-Dec-95 KyleP Created.
  695. //
  696. //----------------------------------------------------------------------------
  697. ULONG * COnDiskPropertyRecord::LeftCompress( ULONG * pul, ULONG cul, ULONG * pulEnd )
  698. {
  699. //
  700. // Terminating recursion? Just copy the allocated info. Used size is
  701. // zero, because data isn't copied.
  702. //
  703. if ( pul == pulEnd )
  704. {
  705. pul -= cul;
  706. SetAllocatedSize( pul, AllocatedSize(*pulEnd) + cul );
  707. SetUsedSize( pul, 0 );
  708. return pul;
  709. }
  710. //
  711. // First, move current record.
  712. //
  713. if ( cul > 0 )
  714. {
  715. RtlMoveMemory( pul - cul, pul, (UsedSize(*pul) + 1) * 4 );
  716. pul -= cul;
  717. }
  718. //
  719. // Adjust allocation size.
  720. //
  721. cul += ( AllocatedSize(*pul) - UsedSize(*pul) );
  722. SetAllocatedSize( pul, UsedSize(*pul) );
  723. return LeftCompress( pul + cul + UsedSize(*pul) + 1, cul, pulEnd );
  724. }
  725. //+---------------------------------------------------------------------------
  726. //
  727. // Member: COnDiskPropertyRecord::IsUnicodeSpecial, private
  728. //
  729. // Synopsis: Determines if variant is Unicode string with all 0 high bytes.
  730. //
  731. // Arguments: [var] -- Variant to check
  732. // [cul] -- On TRUE, returns count of DWORDs needed to store
  733. //
  734. // Returns: TRUE if [var] is a Unicode string with all 0 high bytes.
  735. //
  736. // History: 17-Jul-97 KyleP Created
  737. //
  738. //----------------------------------------------------------------------------
  739. BOOL COnDiskPropertyRecord::IsUnicodeSpecial( CStorageVariant const & var,
  740. ULONG & cul )
  741. {
  742. if ( VT_LPWSTR != var.Type() )
  743. return FALSE;
  744. //
  745. // Loop through string, looking for non-null high bytes.
  746. //
  747. for ( WCHAR const * pwc = var.GetLPWSTR();
  748. 0 != *pwc && 0 == (*pwc & 0xFF00 );
  749. pwc++ )
  750. {
  751. continue; // Null body
  752. }
  753. cul = 1 + // Type (VT_ILLEGAL)
  754. 1 + // Size
  755. (ULONG)(pwc - var.GetLPWSTR() + 3) / sizeof(ULONG); // Characters
  756. return (0 == *pwc);
  757. }
  758. //+---------------------------------------------------------------------------
  759. //
  760. // Member: COnDiskPropertyRecord::IsUnicodeSpecial, private
  761. //
  762. // Synopsis: Determines if serialized property is stored in special
  763. // compressed Unicode format.
  764. //
  765. // Arguments: [pProp] -- Serialized buffer to check.
  766. // [cb] -- On TRUE, returns size in bytes of deserialized
  767. // string.
  768. //
  769. // Returns: TRUE if [pProp] contains Unicode string serialized in special
  770. // format.
  771. //
  772. // History: 17-Jul-97 KyleP Created
  773. //
  774. //----------------------------------------------------------------------------
  775. BOOL COnDiskPropertyRecord::IsUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  776. ULONG & cb )
  777. {
  778. if ( VT_ILLEGAL != pProp->dwType )
  779. return FALSE;
  780. cb = ((*(ULONG *)pProp->rgb) + 1) * sizeof(WCHAR);
  781. return TRUE;
  782. }
  783. //+---------------------------------------------------------------------------
  784. //
  785. // Member: COnDiskPropertyRecord::WriteUnicodeSpecial, private
  786. //
  787. // Synopsis: Serializes 'Special' Unicode string to buffer.
  788. //
  789. // Arguments: [var] -- Contains Unicode string
  790. // [pProp] -- Serialize to here
  791. //
  792. // History: 17-Jul-97 KyleP Created
  793. //
  794. //----------------------------------------------------------------------------
  795. void COnDiskPropertyRecord::WriteUnicodeSpecial( CStorageVariant const & var,
  796. SERIALIZEDPROPERTYVALUE * pProp )
  797. {
  798. Win4Assert( VT_LPWSTR == var.Type() );
  799. pProp->dwType = VT_ILLEGAL;
  800. WCHAR const * pwcIn = var.GetLPWSTR();
  801. for ( unsigned i = 0; 0 != *pwcIn; i++, pwcIn++ )
  802. {
  803. Win4Assert( 0 == (*pwcIn & 0xFF00) );
  804. pProp->rgb[4 + i] = (BYTE)(*pwcIn);
  805. }
  806. *(ULONG *)pProp->rgb = i;
  807. }
  808. //+---------------------------------------------------------------------------
  809. //
  810. // Member: COnDiskPropertyRecord::ReadUnicodeSpecial, private
  811. //
  812. // Synopsis: Deserializes Unicode string stored in 'Special' format.
  813. //
  814. // Arguments: [pProp] -- Serialized buffer
  815. // [var] -- Variant written here
  816. // [pbExtra] -- Memory to use for string itself
  817. //
  818. // History: 17-Jul-97 KyleP Created
  819. //
  820. //----------------------------------------------------------------------------
  821. void COnDiskPropertyRecord::ReadUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  822. PROPVARIANT & var,
  823. BYTE * pbExtra )
  824. {
  825. Win4Assert( VT_ILLEGAL == pProp->dwType );
  826. var.vt = VT_LPWSTR;
  827. ULONG cc = *(ULONG *)pProp->rgb;
  828. var.pwszVal = (WCHAR *)pbExtra;
  829. for ( unsigned i = 0; i < cc; i++ )
  830. {
  831. var.pwszVal[i] = pProp->rgb[4+i];
  832. }
  833. var.pwszVal[i] = 0;
  834. }
  835. //+---------------------------------------------------------------------------
  836. //
  837. // Member: COnDiskPropertyRecord::ReadUnicodeSpecial, private
  838. //
  839. // Synopsis: Deserializes Unicode string stored in 'Special' format. This
  840. // version uses CoTaskMemAlloc for additional memory.
  841. //
  842. // Arguments: [pProp] -- Serialized buffer
  843. // [var] -- Variant written here
  844. //
  845. // History: 17-Jul-97 KyleP Created
  846. //
  847. //----------------------------------------------------------------------------
  848. void COnDiskPropertyRecord::ReadUnicodeSpecialCTMA( SERIALIZEDPROPERTYVALUE const * pProp,
  849. PROPVARIANT & var )
  850. {
  851. Win4Assert( VT_ILLEGAL == pProp->dwType );
  852. var.vt = VT_LPWSTR;
  853. ULONG cc = *(ULONG *)pProp->rgb;
  854. var.pwszVal = (WCHAR *)CoTaskMemAlloc( (cc + 1)*sizeof(WCHAR) );
  855. if ( 0 == var.pwszVal )
  856. {
  857. THROW( CException( E_OUTOFMEMORY ) );
  858. }
  859. for ( unsigned i = 0; i < cc; i++ )
  860. {
  861. var.pwszVal[i] = pProp->rgb[4+i];
  862. }
  863. var.pwszVal[i] = 0;
  864. }