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.

1678 lines
53 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995-2000.
  5. //
  6. // File: PropRec.hxx
  7. //
  8. // Contents: Record format for persistent property store
  9. //
  10. // Classes: CPropertyRecord
  11. //
  12. // History: 28-Dec-19 KyleP Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #pragma once
  16. #include <pstore.hxx>
  17. class CStorageVariant;
  18. const PREV = 0;
  19. const NEXT = 1;
  20. const FREEBLOCKSIZE = 2;
  21. const cFreeListSlots = 3;
  22. //+-------------------------------------------------------------------------
  23. //
  24. // Class: COnDiskPropertyRecord
  25. //
  26. // Purpose: Manipulates property values for single object/record
  27. //
  28. // History: 28-Dec-95 KyleP Created
  29. // 29-May-97 KrishnaN Made records self describing
  30. // 16-Dec-97 KrishnaN Added support for "lean" records
  31. //
  32. // Notes: This class is like a template, that applies structure to a
  33. // single record of a memory-mapped file. Layout of data
  34. // members corresponds exactly to the on-disk version of the
  35. // property store.
  36. //
  37. // There are two types of records "normal" and "lean". Normal
  38. // records have all the support they need to handle overflows,
  39. // variable length records, and variable length properties. The
  40. // "lean" records, on the other hand, can only store fixed
  41. // properties. Since the size of a lean record is always known
  42. // and fixed (until changes to the metadata are made), we don't
  43. // need the ability for overflows and for variable length records.
  44. // That gives us an opportunity to eliminate a significant portion
  45. // of the COnDiskPropertyRecord overhead for a lean record.
  46. //
  47. // Layout of a normal record is as follows:
  48. // 1) Per-record state.
  49. // Count of additional records appended physically
  50. // to this one. Low bit used to indicate record
  51. // is in use.
  52. // Used space in variable property area (in dwords)
  53. // Link to overflow record.
  54. // 2) Existence bitmap. One dword / 16 properties, rounded up
  55. // to nearest dword. First bit (of two) indicates existence.
  56. // Second indicates existence is on overflow.
  57. // 3) Fixed length property storage.
  58. // 4) Variable length property storage. For each property:
  59. // Dword for size.
  60. // High word is size (in dwords) used by current property.
  61. // Low word is allocated size (in dwords).
  62. // Allocated space.
  63. //
  64. //
  65. // Layout of a lean record is as follows:
  66. //
  67. // 1) Existence bitmap. One dword / 16 properties, rounded up
  68. // to nearest dword. First bit (of two) indicates existence.
  69. // Second is unused but left in for compatibility with normal record.
  70. // 3) Fixed length property storage.
  71. //
  72. // Freelist Maintenance:
  73. //
  74. // When a record is not in use, it goes into the free list. This list
  75. // is a doubly linked list sorted by size. The next and prev pointers
  76. // used to be stored in the toplevel and overflow fields of the normal
  77. // record. With the introduction of the lean version of the record,
  78. // which doesn't have the toplevel and overflow fields, we need to
  79. // have two fields to be always present that can be used for link
  80. // tracking. The first and second fields of the data portion, pointed
  81. // to by _aul, will be used to store these ptrs. A third field is needed
  82. // to track the size of the next free block. Therefore the minimum
  83. // size of a record is being modified to include space for _aul[PREV], _aul[NEXT],
  84. // and _aul[FREEBLOCKSIZE]. When we start adding records, we will account for the
  85. // preallocation of these three ULONG fields.
  86. //
  87. //--------------------------------------------------------------------------
  88. #include <pshpack4.h>
  89. class COnDiskPropertyRecord
  90. {
  91. enum ERecType { eVirgin = 0x0000,
  92. eTopLevel = 0xAAAA,
  93. eOverflow = 0x5555,
  94. eFree = 0xBBBB,
  95. eTopLevelLean = 0xCCCC,
  96. eFreeLean = 0xDDDD};
  97. public:
  98. inline void * operator new( size_t size, ULONG record, BYTE * pBase, ULONG culRec );
  99. inline void operator delete( void * p );
  100. inline static ULONG MinStreamSize( ULONG record, ULONG culRec );
  101. //
  102. // Block linking
  103. //
  104. inline WORKID OverflowBlock() const;
  105. inline void SetOverflowBlock( WORKID wid );
  106. inline WORKID ToplevelBlock() const;
  107. inline void SetToplevelBlock( WORKID wid );
  108. inline void ClearToplevelField();
  109. //
  110. // Simple reads / writes.
  111. //
  112. void ReadFixed( ULONG Ordinal,
  113. ULONG Mask,
  114. ULONG oStart,
  115. ULONG cTotal,
  116. ULONG Type,
  117. PROPVARIANT & var,
  118. BYTE * pbExtra,
  119. unsigned * pcbExtra,
  120. PStorage & storage );
  121. BOOL ReadVariable( ULONG Ordinal,
  122. ULONG Mask,
  123. ULONG oStart,
  124. ULONG cTotal,
  125. ULONG cFixed,
  126. PROPVARIANT & var,
  127. BYTE * pbExtra,
  128. unsigned * pcbExtra );
  129. void WriteFixed( ULONG Ordinal,
  130. ULONG Mask,
  131. ULONG oStart,
  132. ULONG Type,
  133. ULONG cTotal,
  134. CStorageVariant const & var );
  135. BOOL WriteVariable( ULONG Ordinal,
  136. ULONG Mask,
  137. ULONG oStart,
  138. ULONG cTotal,
  139. ULONG cFixed,
  140. ULONG culRec,
  141. CStorageVariant const & var,
  142. PStorage & storage );
  143. //
  144. // Multi-record properties.
  145. //
  146. inline BOOL IsLongRecord();
  147. inline ULONG CountRecords() const;
  148. inline void MakeLongRecord( ULONG cRecords );
  149. inline BOOL IsValidType() const;
  150. inline BOOL IsValidInUseRecord( WORKID wid, ULONG cRecPerPage ) const;
  151. inline BOOL IsValidLength( WORKID wid, ULONG cRecPerPage ) const;
  152. inline BOOL AreLinksValid( WORKID widMax ) const;
  153. static ULONG CountNormalRecordsToStore( ULONG cTotal, ULONG culRec,
  154. CStorageVariant const & var );
  155. //
  156. // Free list management
  157. //
  158. inline void MakeNormalFreeRecord( ULONG cRecords, WORKID widNextFree,
  159. ULONG cNextFree, ULONG culRec );
  160. inline void MakeNormalFreeRecord( WORKID widNextFree,
  161. ULONG cNextFree, ULONG culRec );
  162. inline void MakeLeanFreeRecord( ULONG cRecords, WORKID widNextFree,
  163. ULONG cNextFree, ULONG culRec );
  164. inline void MakeLeanFreeRecord( WORKID widNextFree,
  165. ULONG cNextFree, ULONG culRec );
  166. inline ULONG GetNextFreeRecord() const;
  167. inline ULONG GetPreviousFreeRecord() const;
  168. inline ULONG GetNextFreeSize() const;
  169. inline void SetNextFree( WORKID widNextFree, ULONG cNextFree );
  170. inline void SetPreviousFreeRecord( WORKID widPreviousFree );
  171. //
  172. // Overflow records chaining.
  173. //
  174. inline ULONG GetOverflowChainLength() const;
  175. inline void IncrementOverflowChainLength();
  176. inline void SetOverflowChainLength( ULONG cOvfl );
  177. //
  178. // Existence / Use
  179. //
  180. inline BOOL IsInUse() const;
  181. inline BOOL IsTopLevel() const;
  182. inline BOOL IsNormalTopLevel() const;
  183. inline BOOL IsOverflow() const;
  184. inline BOOL IsLeanFreeRecord() const;
  185. inline BOOL IsFreeRecord() const;
  186. inline BOOL IsFreeOrVirginRecord() const;
  187. inline void MakeNewNormalTopLevel();
  188. inline void MakeNewLeanTopLevel();
  189. inline void MakeNewOverflow();
  190. inline void ForceOverflow();
  191. inline void ClearNormal( ULONG culRec );
  192. inline void ClearLean( ULONG culRec );
  193. inline void ClearAll( ULONG culRec );
  194. inline BOOL HasProperties( ULONG cTotal );
  195. inline USHORT Type() const;
  196. inline void SetType(USHORT type);
  197. //
  198. // Reader / Writer
  199. //
  200. inline BOOL IsBeingWritten();
  201. inline BOOL IsBeingRead();
  202. inline void AddReader();
  203. inline void RemoveReader();
  204. inline void AddWriter();
  205. inline void RemoveWriter();
  206. # if CIDBG == 1
  207. inline BOOL LokIsBeingWrittenTwice();
  208. inline BOOL IsNormalEmpty( ULONG culRec );
  209. inline BOOL IsLeanEmpty( ULONG culRec );
  210. # endif
  211. inline static ULONG FixedOverheadLean();
  212. inline static ULONG FixedOverheadNormal();
  213. inline static ULONG MinimalOverheadNormal();
  214. inline BOOL IsStored( ULONG Ordinal, ULONG mask );
  215. inline BOOL IsStoredOnOverflow( ULONG Ordinal, ULONG mask );
  216. //
  217. // Backup support
  218. //
  219. inline void * GetTopLevelFieldAddress() const
  220. {
  221. Win4Assert(!IsLeanRecord());
  222. return (void *) &((SNormalRecord *)&Data)->_ulToplevel;
  223. };
  224. // Lean record support
  225. inline BOOL IsLeanRecord() const
  226. {
  227. return (Type() == eTopLevelLean ||
  228. Type() == eFreeLean);
  229. }
  230. private:
  231. inline void SetStored( ULONG Ordinal, ULONG mask );
  232. inline void ClearStored( ULONG Ordinal, ULONG mask );
  233. inline void SetStoredOnOverflow( ULONG Ordinal, ULONG mask );
  234. inline void ClearStoredOnOverflow( ULONG Ordinal, ULONG mask );
  235. inline static ULONG UsedSize( ULONG ul );
  236. inline static ULONG AllocatedSize( ULONG ul ) { return (ul & 0xFFFF); }
  237. inline static void SetUsedSize( ULONG * pul, ULONG ul );
  238. inline static void SetAllocatedSize( ULONG * pul, ULONG ul );
  239. inline static void MarkOverflow( ULONG * pul );
  240. inline static BOOL IsOverflow( ULONG ul );
  241. inline ULONG FreeVariableSpace( ULONG cTotal, ULONG cFixed, ULONG oStart, ULONG cbRec );
  242. inline ULONG * FindVariableProp( ULONG Ordinal, ULONG cFixed, ULONG cTotal, ULONG oStart );
  243. static void RightCompress( ULONG * pul, ULONG cul, ULONG cRemaining );
  244. static ULONG * LeftCompress( ULONG * pul, ULONG cul, ULONG * pulEnd );
  245. //
  246. // Special optimized Unicode writes.
  247. //
  248. static BOOL IsUnicodeSpecial( CStorageVariant const & var, ULONG & cul );
  249. static BOOL IsUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  250. ULONG & cb );
  251. static void WriteUnicodeSpecial( CStorageVariant const & var,
  252. SERIALIZEDPROPERTYVALUE * pProp );
  253. static void ReadUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  254. PROPVARIANT & var,
  255. BYTE * pbExtra );
  256. static void ReadUnicodeSpecialCTMA( SERIALIZEDPROPERTYVALUE const * pProp,
  257. PROPVARIANT & var );
  258. struct SNormalRecord
  259. {
  260. USHORT _type; // Type of the record
  261. USHORT _cAdditionalRecords; // For long records, size (in records) of long record.
  262. ULONG _culVariableUsed; // Bytes of record that are in use. Variable section only.
  263. WORKID _ulOverflow; // Pointer to overflow block.
  264. WORKID _ulToplevel; // Pointer to the toplevel record. For toplevel
  265. // records, this will be the length of the
  266. // chain.
  267. ULONG _aul[1]; // Rest of block is variable:
  268. // a) Existence bits
  269. // b) Fixed size properties
  270. // c) Variable size properties
  271. };
  272. struct SLeanRecord
  273. {
  274. USHORT _type; // Type of the record
  275. USHORT _cAdditionalRecords; // For long records, size (in records) of long record.
  276. // We only use this field for free list maintenance.
  277. // "In use" lean records are always one record long.
  278. ULONG _aul[1]; // Rest of block is variable:
  279. // a) Existence bits
  280. // b) Fixed size properties
  281. };
  282. // Convenient inline functions
  283. // _cAdditionalRecords is at the same position in both
  284. // structures. Cast to either structure is fine.
  285. inline USHORT AdditionalRecords() const
  286. {
  287. Win4Assert(offsetof(SNormalRecord, _cAdditionalRecords) ==
  288. offsetof(SLeanRecord, _cAdditionalRecords));
  289. return ((SNormalRecord *)&Data)->_cAdditionalRecords;
  290. }
  291. inline void SetAdditionalRecords(USHORT cRecs)
  292. {
  293. Win4Assert(offsetof(SNormalRecord, _cAdditionalRecords) ==
  294. offsetof(SLeanRecord, _cAdditionalRecords));
  295. ((SNormalRecord *)&Data)->_cAdditionalRecords = cRecs;
  296. }
  297. inline ULONG VariableUsed() const
  298. {
  299. Win4Assert(!IsLeanRecord());
  300. return ((SNormalRecord *)&Data)->_culVariableUsed;
  301. }
  302. inline void SetVariableUsed(ULONG ulVarUsed)
  303. {
  304. Win4Assert(!IsLeanRecord());
  305. ((SNormalRecord *)&Data)->_culVariableUsed = ulVarUsed;
  306. }
  307. // All we have is a buffer containing the on-disk bits of the record. Depending
  308. // on the type of the record, we will cast that buffer into SNormalRecord or
  309. // SLeanRecord.
  310. ULONG Data;
  311. };
  312. #include <poppack.h>
  313. //+---------------------------------------------------------------------------
  314. //
  315. // Member: COnDiskPropertyRecord::operator new, public
  316. //
  317. // Synopsis: Special operator new (computes offset of record in file)
  318. //
  319. // Arguments: [size] -- Required (and unused) parameter
  320. // [record] -- Record number
  321. // [pBase] -- Address of record 0
  322. // [culRec] -- Size in dwords of single record
  323. //
  324. // History: 27-Dec-95 KyleP Created.
  325. //
  326. //----------------------------------------------------------------------------
  327. inline void * COnDiskPropertyRecord::operator new( size_t size,
  328. ULONG record,
  329. BYTE * pBase,
  330. ULONG culRec )
  331. {
  332. ciDebugOut(( DEB_PROPSTORE,
  333. "PROPSTORE: Opening record at offset 0x%x (%d)\n",
  334. record * culRec * 4,
  335. record * culRec * 4 ));
  336. return pBase + record * culRec * 4;
  337. }
  338. //+---------------------------------------------------------------------------
  339. //
  340. // Member: COnDiskPropertyRecord::operator delete, public
  341. //
  342. // Synopsis: Just to make sure it isn't called...
  343. //
  344. // History: 27-Dec-95 KyleP Created.
  345. //
  346. //----------------------------------------------------------------------------
  347. inline void COnDiskPropertyRecord::operator delete( void * p )
  348. {
  349. // No action. This is mapped onto a file.
  350. }
  351. // _type is the first field of both SNormalRecord
  352. // and SLeanRecord, so we access it through either
  353. inline USHORT COnDiskPropertyRecord::Type() const
  354. {
  355. return ((SNormalRecord *)&Data)->_type;
  356. }
  357. inline void COnDiskPropertyRecord::SetType(USHORT type)
  358. {
  359. ((SNormalRecord *)&Data)->_type = type;
  360. }
  361. //+---------------------------------------------------------------------------
  362. //
  363. // Member: COnDiskPropertyRecord::IsLongRecord, public
  364. //
  365. // Returns: TRUE if record is long (consists of more than one
  366. // physically contiguous record).
  367. //
  368. // History: 27-Dec-95 KyleP Created.
  369. //
  370. //----------------------------------------------------------------------------
  371. inline BOOL COnDiskPropertyRecord::IsLongRecord()
  372. {
  373. // Lean records can only be long when they are in the free list
  374. #if CIDBG == 1
  375. if (eTopLevelLean == Type())
  376. Win4Assert(0 == AdditionalRecords());
  377. #endif // CIDBG
  378. return ( AdditionalRecords() != 0);
  379. }
  380. //+---------------------------------------------------------------------------
  381. //
  382. // Member: COnDiskPropertyRecord::CountRecords, public
  383. //
  384. // Returns: Size of record (in one-records)
  385. //
  386. // History: 27-Dec-95 KyleP Created.
  387. //
  388. //----------------------------------------------------------------------------
  389. inline ULONG COnDiskPropertyRecord::CountRecords() const
  390. {
  391. // Lean records can only be long when they are in the free list
  392. #if CIDBG == 1
  393. if (eTopLevelLean == Type())
  394. Win4Assert(0 == AdditionalRecords());
  395. #endif // CIDBG
  396. return AdditionalRecords() + 1;
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Member: COnDiskPropertyRecord::MakeLongRecord, public
  401. //
  402. // Synopsis: Indicates record is long.
  403. //
  404. // Arguments: [cRecords] -- Number of physically contiguous records.
  405. //
  406. // History: 27-Dec-95 KyleP Created.
  407. //
  408. //----------------------------------------------------------------------------
  409. inline void COnDiskPropertyRecord::MakeLongRecord( ULONG cRecords )
  410. {
  411. Win4Assert( cRecords >= 1 );
  412. // Win4Assert( !HasProperties( 1 ) );
  413. // Lean records can only be long when they are in the free list
  414. #if CIDBG == 1
  415. if (eTopLevelLean == Type())
  416. Win4Assert(1 == cRecords);
  417. #endif // CIDBG
  418. SetAdditionalRecords((USHORT) (cRecords - 1));
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Member: COnDiskProperyRecord::IsFreeRecord
  423. //
  424. // Synopsis: Tests if the current record is a Free record.
  425. //
  426. // History: 2-23-96 srikants Created
  427. //
  428. //----------------------------------------------------------------------------
  429. inline BOOL COnDiskPropertyRecord::IsFreeRecord() const
  430. {
  431. return (eFreeLean == Type() || eFree == Type());
  432. }
  433. //+---------------------------------------------------------------------------
  434. //
  435. // Member: COnDiskProperyRecord::IsLeanFreeRecord
  436. //
  437. // Synopsis: Tests if the current record is a Lean Free record.
  438. //
  439. // History: Dec-31-97 KrishnaN Created
  440. //
  441. //----------------------------------------------------------------------------
  442. inline BOOL COnDiskPropertyRecord::IsLeanFreeRecord() const
  443. {
  444. return (eFreeLean == Type());
  445. }
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Member: COnDiskProperyRecord::IsFreeOrVirginRecord
  449. //
  450. // Synopsis: Tests if the current record is a Free or a virgin record.
  451. //
  452. // History: 12-03-97 krishnaN Created
  453. //
  454. //----------------------------------------------------------------------------
  455. inline BOOL COnDiskPropertyRecord::IsFreeOrVirginRecord() const
  456. {
  457. return (eFree == Type() || eFreeLean == Type() ||
  458. eVirgin == Type());
  459. }
  460. //+---------------------------------------------------------------------------
  461. //
  462. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  463. //
  464. // Synopsis: Makes the current normal record a free record.
  465. //
  466. // Arguments: [ulNextFree] - The workid of the next free record
  467. // [cFree] - Size of next free record
  468. // [culRec] - Count of ULONGs per record.
  469. //
  470. // History: 4-11-96 srikants Created
  471. //
  472. // Notes: It is assumed that the "_cAdditionalRecords" is correctly set
  473. //
  474. //----------------------------------------------------------------------------
  475. inline void COnDiskPropertyRecord::MakeNormalFreeRecord( WORKID ulNextFree,
  476. ULONG cFree,
  477. ULONG culRec )
  478. {
  479. ClearNormal( culRec );
  480. SetNextFree( ulNextFree, cFree );
  481. }
  482. //+---------------------------------------------------------------------------
  483. //
  484. // Member: COnDiskPropertyRecord::MakeLeanFreeRecord
  485. //
  486. // Synopsis: Makes the current lean record a free record.
  487. //
  488. // Arguments: [ulNextFree] - The workid of the next free record
  489. // [cFree] - Size of next free record
  490. // [culRec] - Count of ULONGs per record.
  491. //
  492. // History: 17-12-97 KrishnaN Created
  493. //
  494. // Notes: It is assumed that the "_cAdditionalRecords" is correctly set
  495. //
  496. //----------------------------------------------------------------------------
  497. inline void COnDiskPropertyRecord::MakeLeanFreeRecord( WORKID ulNextFree,
  498. ULONG cFree,
  499. ULONG culRec )
  500. {
  501. ClearLean( culRec );
  502. SetNextFree( ulNextFree, cFree );
  503. }
  504. //+---------------------------------------------------------------------------
  505. //
  506. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  507. //
  508. // Synopsis: Makes the current record a free record of length "cRecords"
  509. //
  510. // Arguments: [cRecords] - Length of this block in "records"
  511. // [ulNextFree] - The next free record wid
  512. // [cFree] - Size of next free record
  513. // [culRec] - Count of ULONGs per record
  514. //
  515. // History: 4-11-96 srikants Created
  516. //
  517. //----------------------------------------------------------------------------
  518. inline void COnDiskPropertyRecord::MakeNormalFreeRecord(
  519. ULONG cRecords,
  520. WORKID ulNextFree,
  521. ULONG cFree,
  522. ULONG culRec )
  523. {
  524. MakeLongRecord( cRecords );
  525. MakeNormalFreeRecord( ulNextFree, cFree, culRec );
  526. }
  527. //+---------------------------------------------------------------------------
  528. //
  529. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  530. //
  531. // Synopsis: Makes the current record a free record of length "cRecords"
  532. //
  533. // Arguments: [cRecords] - Length of this block in "records"
  534. // [ulNextFree] - The next free record wid
  535. // [cFree] - Size of next free record
  536. // [culRec] - Count of ULONGs per record
  537. //
  538. // History: 12-17-97 KrishnaN Created
  539. //
  540. //----------------------------------------------------------------------------
  541. inline void COnDiskPropertyRecord::MakeLeanFreeRecord(
  542. ULONG cRecords,
  543. WORKID ulNextFree,
  544. ULONG cFree,
  545. ULONG culRec )
  546. {
  547. // Mark it to be a free record before attempting to make it a long
  548. // record.
  549. MakeLeanFreeRecord( ulNextFree, cFree, culRec );
  550. MakeLongRecord( cRecords );
  551. }
  552. //+---------------------------------------------------------------------------
  553. //
  554. // Member: COnDiskPropertyRecord::SetNextFreeRecord
  555. //
  556. // Synopsis: Sets the next free record.
  557. //
  558. // History: 4-10-96 srikants Created
  559. //
  560. //----------------------------------------------------------------------------
  561. inline void COnDiskPropertyRecord::SetNextFree( WORKID widNextFree,
  562. ULONG cNextFree )
  563. {
  564. Win4Assert( IsFreeRecord() );
  565. ULONG *aul;
  566. if (eFree == Type())
  567. aul = ((SNormalRecord *)&Data)->_aul;
  568. else
  569. aul = ((SLeanRecord *)&Data)->_aul;
  570. aul[NEXT] = widNextFree;
  571. aul[FREEBLOCKSIZE] = cNextFree;
  572. }
  573. //+---------------------------------------------------------------------------
  574. //
  575. // Member: COnDiskPropertyRecord::SetPreviousFreeRecord
  576. //
  577. // Synopsis: Sets the previous free record.
  578. //
  579. // History: 4-10-96 srikants Created
  580. //
  581. //----------------------------------------------------------------------------
  582. inline void COnDiskPropertyRecord::SetPreviousFreeRecord( WORKID widPrevFree )
  583. {
  584. Win4Assert( IsFreeRecord() );
  585. if (eFree == Type())
  586. ((SNormalRecord *)&Data)->_aul[PREV] = widPrevFree;
  587. else
  588. ((SLeanRecord *)&Data)->_aul[PREV] = widPrevFree;
  589. }
  590. //+---------------------------------------------------------------------------
  591. //
  592. // Member: COnDiskPropertyRecord::GetNextFreeRecord
  593. //
  594. // Synopsis: Gets the next free record.
  595. //
  596. // History: 4-10-96 srikants Created
  597. //
  598. //----------------------------------------------------------------------------
  599. inline ULONG COnDiskPropertyRecord::GetNextFreeRecord() const
  600. {
  601. Win4Assert( IsFreeRecord() );
  602. if (eFree == Type())
  603. return ((SNormalRecord *)&Data)->_aul[NEXT];
  604. else
  605. return ((SLeanRecord *)&Data)->_aul[NEXT];
  606. }
  607. //+---------------------------------------------------------------------------
  608. //
  609. // Member: COnDiskPropertyRecord::GetPreviousFreeRecord
  610. //
  611. // Synopsis: Gets the previous free record.
  612. //
  613. // History: 4-10-96 srikants Created
  614. //
  615. //----------------------------------------------------------------------------
  616. inline ULONG COnDiskPropertyRecord::GetPreviousFreeRecord() const
  617. {
  618. Win4Assert( IsFreeRecord() );
  619. if (eFree == Type())
  620. return ((SNormalRecord *)&Data)->_aul[PREV];
  621. else
  622. return ((SLeanRecord *)&Data)->_aul[PREV];
  623. }
  624. //+---------------------------------------------------------------------------
  625. //
  626. // Member: COnDiskPropertyRecord::GetNextFreeSize
  627. //
  628. // Synopsis: Gets the next free blocks size.
  629. //
  630. // History: 4-10-96 srikants Created
  631. //
  632. //----------------------------------------------------------------------------
  633. inline ULONG COnDiskPropertyRecord::GetNextFreeSize() const
  634. {
  635. Win4Assert( IsFreeRecord() );
  636. if (eFree == Type())
  637. return ((SNormalRecord *)&Data)->_aul[FREEBLOCKSIZE];
  638. else
  639. return ((SLeanRecord *)&Data)->_aul[FREEBLOCKSIZE];
  640. }
  641. //+---------------------------------------------------------------------------
  642. //
  643. // Member: COnDiskPropertyRecord::MinStreamSize, public
  644. //
  645. // Synopsis: Computes position of record in stream
  646. //
  647. // Arguments: [record] -- Record number
  648. // [culRec] -- Size in dwords of single record
  649. //
  650. // Returns: Minimum size stream that can hold this record.
  651. //
  652. // History: 27-Dec-95 KyleP Created.
  653. //
  654. //----------------------------------------------------------------------------
  655. inline ULONG COnDiskPropertyRecord::MinStreamSize( ULONG record, ULONG culRec )
  656. {
  657. return (record + 1) * culRec * 4;
  658. }
  659. //+---------------------------------------------------------------------------
  660. //
  661. // Member: COnDiskPropertyRecord::OverflowBlock, public
  662. //
  663. // Returns: Overflow block id (zero if no overflow block)
  664. //
  665. // History: 27-Dec-95 KyleP Created.
  666. //
  667. //
  668. //----------------------------------------------------------------------------
  669. inline WORKID COnDiskPropertyRecord::OverflowBlock() const
  670. {
  671. Win4Assert(!IsLeanRecord());
  672. return ((SNormalRecord *)&Data)->_ulOverflow;
  673. }
  674. //+---------------------------------------------------------------------------
  675. //
  676. // Member: COnDiskPropertyRecord::SetOverflowBlock, public
  677. //
  678. // Synopsis: Sets overflow block id (zero if no overflow block)
  679. //
  680. // Arguments: [wid] -- Workid (record number) of link
  681. //
  682. // History: 27-Dec-95 KyleP Created.
  683. //
  684. //----------------------------------------------------------------------------
  685. inline void COnDiskPropertyRecord::SetOverflowBlock( WORKID wid )
  686. {
  687. Win4Assert(!IsLeanRecord());
  688. ((SNormalRecord *)&Data)->_ulOverflow = wid;
  689. }
  690. //+---------------------------------------------------------------------------
  691. //
  692. // Member: COnDiskPropertyRecord::ToplevelBlock
  693. //
  694. // Synopsis: Returns the previous block value.
  695. //
  696. // History: 4-10-96 srikants Created
  697. //
  698. // Notes: For a top-level record, this will be the length of the
  699. // overflow chain records.
  700. // For a free list record, this will be the size of the next
  701. // free block in the list.
  702. //
  703. //----------------------------------------------------------------------------
  704. inline WORKID COnDiskPropertyRecord::ToplevelBlock() const
  705. {
  706. Win4Assert(!IsLeanRecord());
  707. return ((SNormalRecord *)&Data)->_ulToplevel;
  708. }
  709. //+---------------------------------------------------------------------------
  710. //
  711. // Member: COnDiskPropertyRecord::SetToplevelBlock
  712. //
  713. // Synopsis: Updates the previous block value.
  714. //
  715. // Arguments: [widPrev] - Value of the previous block
  716. //
  717. // History: 4-10-96 srikants Created
  718. //
  719. //----------------------------------------------------------------------------
  720. inline void COnDiskPropertyRecord::SetToplevelBlock( WORKID widToplevel )
  721. {
  722. Win4Assert( eOverflow == Type() );
  723. ((SNormalRecord *)&Data)->_ulToplevel = widToplevel;
  724. }
  725. //+---------------------------------------------------------------------------
  726. //
  727. // Member: COnDiskPropertyRecord::ClearToplevelField, public
  728. //
  729. // Arguments:
  730. //
  731. // History: 4-10-96 srikants Created
  732. //
  733. //----------------------------------------------------------------------------
  734. inline void COnDiskPropertyRecord::ClearToplevelField()
  735. {
  736. Win4Assert( eFree == Type() || eVirgin == Type() );
  737. // can't use SetToplevelBlock because that is to be used
  738. // only with overflow records.
  739. ((SNormalRecord *)&Data)->_ulToplevel = 0;
  740. }
  741. //+---------------------------------------------------------------------------
  742. //
  743. // Member: COnDiskPropertyRecord::GetOverflowChainLength, public
  744. //
  745. // Arguments:
  746. //
  747. // History: 4-10-96 srikants Created
  748. //
  749. //----------------------------------------------------------------------------
  750. inline ULONG COnDiskPropertyRecord::GetOverflowChainLength() const
  751. {
  752. Win4Assert( eTopLevel == Type() );
  753. return ToplevelBlock();
  754. }
  755. //+---------------------------------------------------------------------------
  756. //
  757. // Member: COnDiskPropertyRecord::IncrementOverflowChainLength, public
  758. //
  759. // Arguments:
  760. //
  761. // History: 4-10-96 srikants Created
  762. //
  763. //----------------------------------------------------------------------------
  764. inline void COnDiskPropertyRecord::IncrementOverflowChainLength()
  765. {
  766. Win4Assert( eTopLevel == Type() );
  767. (((SNormalRecord *)&Data)->_ulToplevel)++;
  768. }
  769. //+---------------------------------------------------------------------------
  770. //
  771. // Member: COnDiskPropertyRecord::SetOverflowChainLength, public
  772. //
  773. // Arguments: [cCount] -- Size of overflow chain
  774. //
  775. // History: 4-10-96 srikants Created
  776. //
  777. //----------------------------------------------------------------------------
  778. inline void COnDiskPropertyRecord::SetOverflowChainLength( ULONG cCount )
  779. {
  780. Win4Assert( !IsLeanRecord() );
  781. // can't use SetToplevelBlock because that is to be used
  782. // only with overflow records.
  783. ((SNormalRecord *)&Data)->_ulToplevel = cCount;
  784. }
  785. //+---------------------------------------------------------------------------
  786. //
  787. // Member: COnDiskPropertyRecord::IsInUse, public
  788. //
  789. // Returns: TRUE if record is in use.
  790. //
  791. // History: 27-Dec-95 KyleP Created.
  792. //
  793. //----------------------------------------------------------------------------
  794. inline BOOL COnDiskPropertyRecord::IsInUse() const
  795. {
  796. return (eTopLevel == Type() || eOverflow == Type() ||
  797. eTopLevelLean == Type());
  798. }
  799. //+---------------------------------------------------------------------------
  800. //
  801. // Member: COnDiskPropertyRecord::HasProperties, public
  802. //
  803. // Arguments: [cTotal] -- Total number of properties in record.
  804. //
  805. // Returns: TRUE if record has properties stored on it. May be
  806. // in use. Used for debugging.
  807. //
  808. // History: 22-Feb-96 KyleP Created.
  809. //
  810. //----------------------------------------------------------------------------
  811. inline BOOL COnDiskPropertyRecord::HasProperties( ULONG cTotal )
  812. {
  813. ULONG *aul;
  814. // This won't work if we have a "lean virgin" record. In that case,
  815. // we need to have separate functions for lean and normal records.
  816. Win4Assert(eVirgin != Type());
  817. if (IsLeanRecord())
  818. aul = ((SLeanRecord *)&Data)->_aul;
  819. else
  820. aul = ((SNormalRecord *)&Data)->_aul;
  821. for ( ULONG cBitWords = ((cTotal-1) / 16) + 1; cBitWords > 0; cBitWords-- )
  822. {
  823. if ( aul[cBitWords-1] != 0 )
  824. return TRUE;
  825. }
  826. return FALSE;
  827. }
  828. //+---------------------------------------------------------------------------
  829. //
  830. // Member: COnDiskPropertyRecord::MakeNewNormalTopLevel
  831. //
  832. // Synopsis: Marks the current record as a normal top level record.
  833. //
  834. // History: 2-23-96 srikants Created
  835. //
  836. //----------------------------------------------------------------------------
  837. inline void COnDiskPropertyRecord::MakeNewNormalTopLevel()
  838. {
  839. Win4Assert(!IsLeanRecord());
  840. SetType(eTopLevel);
  841. ((SNormalRecord *)&Data)->_ulToplevel =
  842. ((SNormalRecord *)&Data)->_ulOverflow = 0; // Setting the length of overflow chain
  843. SetVariableUsed(0);
  844. // reset the ULONGs of _aul used for free list mgmt.
  845. RtlZeroMemory(((SNormalRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  846. }
  847. //+---------------------------------------------------------------------------
  848. //
  849. // Member: COnDiskPropertyRecord::MakeNewLeanTopLevel
  850. //
  851. // Synopsis: Marks the current record as a lean top level record.
  852. //
  853. // History: 17-Dec-97 KrishnaN Created
  854. //
  855. //----------------------------------------------------------------------------
  856. inline void COnDiskPropertyRecord::MakeNewLeanTopLevel()
  857. {
  858. SetType(eTopLevelLean);
  859. // reset the ULONGs of _aul used for free list mgmt.
  860. RtlZeroMemory(((SLeanRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  861. }
  862. //+---------------------------------------------------------------------------
  863. //
  864. // Member: COnDiskProperyRecord::IsTopLevel
  865. //
  866. // Synopsis: Tests if the current record is a TopLevel record.
  867. //
  868. // History: 2-23-96 srikants Created
  869. //
  870. //----------------------------------------------------------------------------
  871. inline BOOL COnDiskPropertyRecord::IsTopLevel() const
  872. {
  873. return (eTopLevel == Type() || eTopLevelLean == Type());
  874. }
  875. //+---------------------------------------------------------------------------
  876. //
  877. // Member: COnDiskProperyRecord::IsNormalTopLevel
  878. //
  879. // Synopsis: Tests if the current record is a TopLevel record.
  880. //
  881. // History: 2-23-96 srikants Created
  882. //
  883. //----------------------------------------------------------------------------
  884. inline BOOL COnDiskPropertyRecord::IsNormalTopLevel() const
  885. {
  886. return (eTopLevel == Type());
  887. }
  888. //+---------------------------------------------------------------------------
  889. //
  890. // Member: COnDiskPropertyRecord::MakeNewOverflow
  891. //
  892. // Synopsis: Marks the record as an overflow record
  893. //
  894. // History: 4-10-96 srikants Created
  895. //
  896. //----------------------------------------------------------------------------
  897. inline void COnDiskPropertyRecord::MakeNewOverflow()
  898. {
  899. Win4Assert(!IsLeanRecord());
  900. SetType(eOverflow);
  901. ((SNormalRecord *)&Data)->_ulToplevel =
  902. ((SNormalRecord *)&Data)->_ulOverflow = 0; // Setting the length of overflow chain
  903. SetVariableUsed(0);
  904. // reset the ULONGs of _aul used for free list mgmt.
  905. RtlZeroMemory(((SNormalRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  906. }
  907. inline void COnDiskPropertyRecord::ForceOverflow()
  908. {
  909. Win4Assert(!IsLeanRecord());
  910. SetType(eOverflow);
  911. }
  912. //+---------------------------------------------------------------------------
  913. //
  914. // Member: COnDiskPropertyRecord::IsOverflow
  915. //
  916. // Synopsis: Tests if this is an overflow record.
  917. //
  918. // History: 4-10-96 srikants Created
  919. //
  920. //----------------------------------------------------------------------------
  921. inline BOOL COnDiskPropertyRecord::IsOverflow() const
  922. {
  923. return eOverflow == Type();
  924. }
  925. //+---------------------------------------------------------------------------
  926. //
  927. // Member: COnDiskPropertyRecord::IsValidLength
  928. //
  929. // Synopsis: Tests if the length is valid for this record for the given
  930. // WORKID and records per page. A record can never span page and
  931. // so the WORKID will help us determine if the length is valid
  932. // or not.
  933. //
  934. // Arguments: [wid] - WORKID of this record
  935. // [cRecPerPage] - Number of records per page.
  936. //
  937. // History: 4-10-96 srikants Created
  938. //
  939. //----------------------------------------------------------------------------
  940. inline BOOL COnDiskPropertyRecord::IsValidLength( WORKID wid, ULONG cRecPerPage ) const
  941. {
  942. WORKID offset = wid % cRecPerPage;
  943. // Lean records can only be long when they are in the free list
  944. #if CIDBG == 1
  945. if (eTopLevelLean == Type())
  946. Win4Assert(0 == AdditionalRecords());
  947. #endif // CIDBG
  948. return offset+AdditionalRecords() < cRecPerPage;
  949. }
  950. inline BOOL COnDiskPropertyRecord::IsValidInUseRecord( WORKID wid, ULONG cRecPerPage ) const
  951. {
  952. if ( eTopLevel == Type() || eOverflow == Type() || eTopLevelLean == Type() )
  953. {
  954. return IsValidLength( wid, cRecPerPage );
  955. }
  956. else
  957. return FALSE;
  958. }
  959. inline BOOL COnDiskPropertyRecord::IsValidType() const
  960. {
  961. return eTopLevel == Type() ||
  962. eOverflow == Type() ||
  963. eFree == Type() ||
  964. eVirgin == Type() ||
  965. eFreeLean == Type() ||
  966. eTopLevelLean== Type();
  967. }
  968. //+---------------------------------------------------------------------------
  969. //
  970. // Member: COnDiskPropertyRecord::AreLinksValid
  971. //
  972. // Synopsis: Tests if the forward and backward links are valid given the
  973. // widMax.
  974. //
  975. // Arguments: [widMax] - The maximum workid that is in use for the entire
  976. // property store.
  977. //
  978. // History: 4-10-96 srikants Created
  979. //
  980. //----------------------------------------------------------------------------
  981. inline BOOL COnDiskPropertyRecord::AreLinksValid( WORKID widMax ) const
  982. {
  983. // If this method is used for free or virgin records, we will need a
  984. // conditional return. The links for free records are in _aul[PREV] and _aul[NEXT].
  985. Win4Assert(!IsFreeOrVirginRecord());
  986. if (IsLeanRecord())
  987. return TRUE; // no links to worry about.
  988. else
  989. return OverflowBlock() <= widMax && ToplevelBlock() <= widMax;
  990. }
  991. //+---------------------------------------------------------------------------
  992. //
  993. // Member: COnDiskPropertyRecord::ClearNormal, public
  994. //
  995. // Synopsis: Zero complete normal record.
  996. //
  997. // Arguments: [culRec] -- Size in dwords of record
  998. //
  999. // History: 27-Dec-95 KyleP Created.
  1000. //
  1001. //----------------------------------------------------------------------------
  1002. inline void COnDiskPropertyRecord::ClearNormal( ULONG culRec )
  1003. {
  1004. Win4Assert( 2 == offsetof( SNormalRecord, _cAdditionalRecords ) );
  1005. Win4Assert( 4 == offsetof( SNormalRecord, _culVariableUsed ) );
  1006. RtlZeroMemory( &((SNormalRecord *)&Data)->_culVariableUsed,
  1007. culRec * CountRecords() * sizeof (ULONG) -
  1008. offsetof( SNormalRecord, _culVariableUsed ) );
  1009. SetType(eFree);
  1010. }
  1011. //+---------------------------------------------------------------------------
  1012. //
  1013. // Member: COnDiskPropertyRecord::ClearLean, public
  1014. //
  1015. // Synopsis: Zero complete lean record.
  1016. //
  1017. // Arguments: [culRec] -- Size in dwords of record
  1018. //
  1019. // History: 17-Dec-97 KrishnaN Created.
  1020. //
  1021. //----------------------------------------------------------------------------
  1022. inline void COnDiskPropertyRecord::ClearLean( ULONG culRec )
  1023. {
  1024. RtlZeroMemory( ((SLeanRecord *)&Data)->_aul,
  1025. culRec * CountRecords() * sizeof (ULONG) -
  1026. offsetof( SLeanRecord, _aul ) );
  1027. SetType(eFreeLean);
  1028. }
  1029. //+---------------------------------------------------------------------------
  1030. //
  1031. // Member: COnDiskPropertyRecord::ClearAll
  1032. //
  1033. // Synopsis: Clears the entire record to be 0 filled.
  1034. //
  1035. // Arguments: [culRec] -
  1036. //
  1037. // History: 3-25-96 srikants Created
  1038. //
  1039. //----------------------------------------------------------------------------
  1040. inline void COnDiskPropertyRecord::ClearAll( ULONG culRec )
  1041. {
  1042. RtlZeroMemory(&Data, culRec*sizeof(ULONG));
  1043. }
  1044. //+---------------------------------------------------------------------------
  1045. //
  1046. // Member: COnDiskPropertyRecord::FixedOverheadNormal, public
  1047. //
  1048. // Returns: Size of normal record including 3 dwords for free list mgmt.
  1049. //
  1050. // History: 27-Dec-95 KyleP Created.
  1051. //
  1052. //----------------------------------------------------------------------------
  1053. inline ULONG COnDiskPropertyRecord::FixedOverheadNormal()
  1054. {
  1055. // We need to preallocate the first three ULONGs of the variable
  1056. // section of the record for free list mgmt.
  1057. return ((ULONG) (ULONG_PTR)&((SNormalRecord *)0)->_aul[3]) / sizeof(ULONG);
  1058. }
  1059. //+---------------------------------------------------------------------------
  1060. //
  1061. // Member: COnDiskPropertyRecord::MinimalOverheadNormal, public
  1062. //
  1063. // Returns: Size of normal record, sans uninterpreted variable area.
  1064. //
  1065. // History: 27-Dec-95 KyleP Created.
  1066. //
  1067. //----------------------------------------------------------------------------
  1068. inline ULONG COnDiskPropertyRecord::MinimalOverheadNormal()
  1069. {
  1070. // Just the minimal overhead of a normal record
  1071. return ((ULONG) (ULONG_PTR)&((SNormalRecord *)0)->_aul[0]) / sizeof(ULONG);
  1072. }
  1073. //+---------------------------------------------------------------------------
  1074. //
  1075. // Member: COnDiskPropertyRecord::FixedOverheadLean, public
  1076. //
  1077. // Returns: Size of lean record, sans uninterpreted variable area.
  1078. //
  1079. // History: 17-Dec-97 KrishnaN Created.
  1080. //
  1081. //----------------------------------------------------------------------------
  1082. inline ULONG COnDiskPropertyRecord::FixedOverheadLean()
  1083. {
  1084. // We need to preallocate the first three ULONGs of the variable
  1085. // section of the record for free list mgmt.
  1086. return ((ULONG) (ULONG_PTR)&((SLeanRecord *)0)->_aul[3]) / sizeof(ULONG);
  1087. }
  1088. //+---------------------------------------------------------------------------
  1089. //
  1090. // Member: COnDiskPropertyRecord::IsStored, public
  1091. //
  1092. // Synopsis: Test property existence.
  1093. //
  1094. // Arguments: [Ordinal] -- Position of property in list.
  1095. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1096. //
  1097. // Returns: TRUE if property at [Ordinal] is stored.
  1098. //
  1099. // History: 27-Dec-95 KyleP Created.
  1100. //
  1101. //----------------------------------------------------------------------------
  1102. inline BOOL COnDiskPropertyRecord::IsStored( ULONG Ordinal, ULONG mask )
  1103. {
  1104. Win4Assert(eVirgin != Type());
  1105. ULONG *aul;
  1106. if (IsLeanRecord())
  1107. aul = ((SLeanRecord *)&Data)->_aul;
  1108. else
  1109. aul = ((SNormalRecord *)&Data)->_aul;
  1110. return ( (aul[Ordinal / 16] & mask) != 0 );
  1111. }
  1112. //+---------------------------------------------------------------------------
  1113. //
  1114. // Member: COnDiskPropertyRecord::SetStored, public
  1115. //
  1116. // Synopsis: Marks property as stored.
  1117. //
  1118. // Arguments: [Ordinal] -- Position of property in list.
  1119. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1120. //
  1121. // History: 27-Dec-95 KyleP Created.
  1122. //
  1123. //----------------------------------------------------------------------------
  1124. inline void COnDiskPropertyRecord::SetStored( ULONG Ordinal, ULONG mask )
  1125. {
  1126. Win4Assert(eVirgin != Type());
  1127. ULONG *aul;
  1128. if (IsLeanRecord())
  1129. aul = ((SLeanRecord *)&Data)->_aul;
  1130. else
  1131. aul = ((SNormalRecord *)&Data)->_aul;
  1132. aul[Ordinal / 16] |= mask;
  1133. }
  1134. //+---------------------------------------------------------------------------
  1135. //
  1136. // Member: COnDiskPropertyRecord::ClearStored, public
  1137. //
  1138. // Synopsis: Marks property as not stored.
  1139. //
  1140. // Arguments: [Ordinal] -- Position of property in list.
  1141. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1142. //
  1143. // History: 27-Dec-95 KyleP Created.
  1144. //
  1145. //----------------------------------------------------------------------------
  1146. inline void COnDiskPropertyRecord::ClearStored( ULONG Ordinal, ULONG mask )
  1147. {
  1148. Win4Assert(eVirgin != Type());
  1149. ULONG *aul;
  1150. if (IsLeanRecord())
  1151. aul = ((SLeanRecord *)&Data)->_aul;
  1152. else
  1153. aul = ((SNormalRecord *)&Data)->_aul;
  1154. aul[Ordinal / 16] &= ~mask;
  1155. }
  1156. //+---------------------------------------------------------------------------
  1157. //
  1158. // Member: COnDiskPropertyRecord::IsStoredOnOverflow, public
  1159. //
  1160. // Synopsis: Test property overflow.
  1161. //
  1162. // Arguments: [Ordinal] -- Position of property in list.
  1163. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1164. //
  1165. // Returns: TRUE if property at [Ordinal] is stored on overflow record.
  1166. //
  1167. // History: 27-Dec-95 KyleP Created.
  1168. //
  1169. //----------------------------------------------------------------------------
  1170. inline BOOL COnDiskPropertyRecord::IsStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1171. {
  1172. Win4Assert( !IsLeanRecord() );
  1173. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1174. return ( ( ((SNormalRecord *)&Data)->_aul[Ordinal / 16] & (mask << 1)) != 0 );
  1175. }
  1176. //+---------------------------------------------------------------------------
  1177. //
  1178. // Member: COnDiskPropertyRecord::SetStoredOnOverflow, public
  1179. //
  1180. // Synopsis: Marks property as stored on overflow record.
  1181. //
  1182. // Arguments: [Ordinal] -- Position of property in list.
  1183. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1184. //
  1185. // History: 27-Dec-95 KyleP Created.
  1186. //
  1187. //----------------------------------------------------------------------------
  1188. inline void COnDiskPropertyRecord::SetStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1189. {
  1190. Win4Assert( !IsLeanRecord() );
  1191. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1192. ((SNormalRecord *)&Data)->_aul[Ordinal / 16] |= (mask << 1);
  1193. }
  1194. //+---------------------------------------------------------------------------
  1195. //
  1196. // Member: COnDiskPropertyRecord::ClearStoredOnOverflow, public
  1197. //
  1198. // Synopsis: Marks property as not stored on overflow record.
  1199. //
  1200. // Arguments: [Ordinal] -- Position of property in list.
  1201. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1202. //
  1203. // History: 27-Dec-95 KyleP Created.
  1204. //
  1205. //----------------------------------------------------------------------------
  1206. inline void COnDiskPropertyRecord::ClearStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1207. {
  1208. Win4Assert( !IsLeanRecord() );
  1209. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1210. ((SNormalRecord *)&Data)->_aul[Ordinal / 16] &= ~(mask << 1);
  1211. }
  1212. //+---------------------------------------------------------------------------
  1213. //
  1214. // Member: COnDiskPropertyRecord::UsedSize, public
  1215. //
  1216. // Arguments: [ul] -- Dword containing used/alloced size fields.
  1217. //
  1218. // Returns: Used size.
  1219. //
  1220. // History: 27-Dec-95 KyleP Created.
  1221. //
  1222. //----------------------------------------------------------------------------
  1223. inline ULONG COnDiskPropertyRecord::UsedSize( ULONG ul )
  1224. {
  1225. ULONG size = ul >> 16;
  1226. if ( size == 0xFFFF)
  1227. size = 0;
  1228. return size;
  1229. }
  1230. //+---------------------------------------------------------------------------
  1231. //
  1232. // Member: COnDiskPropertyRecord::SetUsedSize, public
  1233. //
  1234. // Synopsis: Sets used size.
  1235. //
  1236. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1237. // [ul] -- New used size
  1238. //
  1239. // History: 27-Dec-95 KyleP Created.
  1240. //
  1241. //----------------------------------------------------------------------------
  1242. inline void COnDiskPropertyRecord::SetUsedSize( ULONG * pul, ULONG ul )
  1243. {
  1244. Win4Assert( AllocatedSize(*pul) >= ul || ul == 0xFFFF );
  1245. *pul = (*pul & 0xFFFF) | (ul << 16);
  1246. }
  1247. //+---------------------------------------------------------------------------
  1248. //
  1249. // Member: COnDiskPropertyRecord::SetAllocatedSize, public
  1250. //
  1251. // Synopsis: Sets allocated size.
  1252. //
  1253. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1254. // [ul] -- New allocated size
  1255. //
  1256. // History: 27-Dec-95 KyleP Created.
  1257. //
  1258. //----------------------------------------------------------------------------
  1259. inline void COnDiskPropertyRecord::SetAllocatedSize( ULONG * pul, ULONG ul )
  1260. {
  1261. Win4Assert( (ul >> 16) == 0 );
  1262. *pul = (*pul & 0xFFFF0000) | ul;
  1263. }
  1264. //+---------------------------------------------------------------------------
  1265. //
  1266. // Member: COnDiskPropertyRecord::MarkOverflow, public
  1267. //
  1268. // Synopsis: Indicates variable stored in overflow record.
  1269. //
  1270. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1271. //
  1272. // History: 27-Dec-95 KyleP Created.
  1273. //
  1274. //----------------------------------------------------------------------------
  1275. inline void COnDiskPropertyRecord::MarkOverflow( ULONG * pul )
  1276. {
  1277. SetUsedSize( pul, 0xFFFF );
  1278. }
  1279. //+---------------------------------------------------------------------------
  1280. //
  1281. // Member: COnDiskPropertyRecord::IsOverflow, public
  1282. //
  1283. // Arguments: [ul] -- dword containing used/alloced size fields.
  1284. //
  1285. // Returns: TRUE if variable is in overflow record.
  1286. //
  1287. // History: 27-Dec-95 KyleP Created.
  1288. //
  1289. //----------------------------------------------------------------------------
  1290. inline BOOL COnDiskPropertyRecord::IsOverflow( ULONG ul )
  1291. {
  1292. return ((ul & 0xFFFF0000) == 0xFFFF0000);
  1293. }
  1294. //+---------------------------------------------------------------------------
  1295. //
  1296. // Member: COnDiskPropertyRecord::FreeVariableSpace, public
  1297. //
  1298. // Synopsis: Compute free space.
  1299. //
  1300. // Arguments: [cTotal] -- Total number of properties in record.
  1301. // [cFixed] -- Count of fixed properties in record.
  1302. // [oStart] -- Offset to start of variable storage area
  1303. // [culRec] -- Size in dwords of record.
  1304. //
  1305. // Returns: Unused variable space in record.
  1306. //
  1307. // History: 27-Dec-95 KyleP Created.
  1308. //
  1309. //----------------------------------------------------------------------------
  1310. inline ULONG COnDiskPropertyRecord::FreeVariableSpace( ULONG cTotal,
  1311. ULONG cFixed,
  1312. ULONG oStart,
  1313. ULONG culRec )
  1314. {
  1315. Win4Assert( !IsLeanRecord() );
  1316. LONG lFree = (culRec * CountRecords()) - // Record size
  1317. MinimalOverheadNormal() - // Minimal fixed overhead
  1318. ((cTotal - 1) / 16 + 1) - // Existence bitmap
  1319. oStart - // Fixed property storage
  1320. (cTotal - cFixed) - // Used/Alloc sizes
  1321. VariableUsed(); // Variable properties
  1322. Win4Assert(lFree >= 0);
  1323. return (ULONG) lFree;
  1324. }
  1325. //+---------------------------------------------------------------------------
  1326. //
  1327. // Member: COnDiskPropertyRecord::FindVariableProp, public
  1328. //
  1329. // Synopsis: Locate start of property.
  1330. //
  1331. // Arguments: [Ordinal] -- Ordinal of property to locate.
  1332. // [cFixed] -- Count of fixed properties in record.
  1333. // [cTotal] -- Total number of properties in record.
  1334. // [oStart] -- Offset to start of variable storage area.
  1335. //
  1336. // Returns: Pointer to start of property
  1337. //
  1338. // History: 27-Dec-95 KyleP Created.
  1339. //
  1340. //----------------------------------------------------------------------------
  1341. inline ULONG * COnDiskPropertyRecord::FindVariableProp( ULONG Ordinal,
  1342. ULONG cFixed,
  1343. ULONG cTotal,
  1344. ULONG oStart )
  1345. {
  1346. Win4Assert( !IsLeanRecord() );
  1347. ciDebugOut(( DEB_PROPSTORE,
  1348. "Ordinal = %d, %d fixed, %d total, offset = 0x%x\n",
  1349. Ordinal, cFixed, cTotal, oStart ));
  1350. //
  1351. // Start is after existance bitmap and fixed properties.
  1352. //
  1353. ULONG * pulVarRecord = &((SNormalRecord *)&Data)->_aul[(cTotal-1) / 16 + 1 + oStart];
  1354. #if CIDBG
  1355. ULONG culUsed = 0;
  1356. #endif // CIDBG
  1357. //
  1358. // Skip over variable props. The "+1" is for the allocation dword.
  1359. //
  1360. for ( ULONG i = cFixed; i < Ordinal; i++ )
  1361. {
  1362. ciDebugOut(( DEB_PROPSTORE, "Ordinal %d starts at offset 0x%x (%d)\n",
  1363. i,
  1364. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this),
  1365. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this) ));
  1366. #if CIDBG
  1367. culUsed += UsedSize(*pulVarRecord);
  1368. #endif
  1369. pulVarRecord += AllocatedSize(*pulVarRecord) + 1;
  1370. }
  1371. ciDebugOut(( DEB_PROPSTORE, "Ordinal %d starts at offset 0x%x (%d)\n",
  1372. i,
  1373. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this),
  1374. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this) ));
  1375. Win4Assert( culUsed + UsedSize(*pulVarRecord) <= VariableUsed() );
  1376. return pulVarRecord;
  1377. }
  1378. #if CIDBG == 1
  1379. //+---------------------------------------------------------------------------
  1380. //
  1381. // Member: COnDiskPropertyRecord::IsNormalEmpty, public
  1382. //
  1383. // Arguments: [culRec] -- Size of record.
  1384. //
  1385. // Returns: TRUE if the normal record is empty.
  1386. //
  1387. // History: 19-Dec-97 KrishnaN Created.
  1388. //
  1389. //----------------------------------------------------------------------------
  1390. inline BOOL COnDiskPropertyRecord::IsNormalEmpty( ULONG culRec )
  1391. {
  1392. BOOL fEmpty = ( 0 == VariableUsed() &&
  1393. 0 == OverflowBlock() &&
  1394. 0 == ToplevelBlock() );
  1395. for ( ULONG i = 0; i < (culRec-5); i++ )
  1396. {
  1397. if ( 0 != ((SNormalRecord *)&Data)->_aul[i] )
  1398. {
  1399. fEmpty = FALSE;
  1400. break;
  1401. }
  1402. }
  1403. return fEmpty;
  1404. }
  1405. //+---------------------------------------------------------------------------
  1406. //
  1407. // Member: COnDiskPropertyRecord::IsLeanEmpty, public
  1408. //
  1409. // Arguments: [culRec] -- Size of record.
  1410. //
  1411. // Returns: TRUE if the lean record is empty.
  1412. //
  1413. // History: 19-Dec-97 KrishnaN Created.
  1414. //
  1415. //----------------------------------------------------------------------------
  1416. inline BOOL COnDiskPropertyRecord::IsLeanEmpty( ULONG culRec )
  1417. {
  1418. BOOL fEmpty = TRUE;
  1419. for ( ULONG i = 0; i < (culRec-1); i++ )
  1420. {
  1421. if ( 0 != ((SLeanRecord *)&Data)->_aul[i] )
  1422. {
  1423. fEmpty = FALSE;
  1424. break;
  1425. }
  1426. }
  1427. return fEmpty;
  1428. }
  1429. #endif // CIDBG