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.

469 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: BITSTM.hxx
  7. //
  8. // Contents: 'Bit streams'
  9. //
  10. // Classes: CBitStream, CWBitStream, CPBitStream, CRBitStream
  11. //
  12. // History: 03-Jul-91 KyleP Created
  13. // 24-Aug-92 BartoszM Rewrote it
  14. //
  15. //----------------------------------------------------------------------------
  16. #pragma once
  17. #include <bitoff.hxx>
  18. #include "physidx.hxx"
  19. #include <ci64.hxx>
  20. class CSmartBuffer
  21. {
  22. public:
  23. enum EAccessMode { eReadExisting, eWriteExisting };
  24. CSmartBuffer ( CPhysStorage& phStorage, EAccessMode mode );
  25. CSmartBuffer ( CPhysStorage& phStorage, BOOL fCreate );
  26. CSmartBuffer ( CPhysStorage& phStorage, ULONG numPage, EAccessMode mode, BOOL fIncrSig = TRUE );
  27. CSmartBuffer ( CSmartBuffer& buf, ULONG numPage );
  28. ~CSmartBuffer ();
  29. ULONG PageNum() { return _numPage; }
  30. __forceinline ULONG* Get() { return _pBuffer + 1; }
  31. BOOL isEmpty() { return _pBuffer == 0; }
  32. void Refill ( ULONG numPage );
  33. ULONG* Next();
  34. ULONG* NextNew();
  35. void Free();
  36. BOOL IsWritable() { return _phStorage.IsWritable(); }
  37. WCHAR const * GetPath() { return _phStorage.GetPath(); }
  38. void InitSignature();
  39. #ifdef CIEXTMODE
  40. void CiExtDump(void *ciExtSelf);
  41. #endif
  42. private:
  43. void CheckCorruption();
  44. void IncrementSig();
  45. CPhysStorage& _phStorage; // Source of pages
  46. ULONG _numPage; // current page number
  47. ULONG * _pBuffer; // Beginning of buffer.
  48. BOOL _fWritable; // Access mode for existing buffers.
  49. };
  50. //+---------------------------------------------------------------------------
  51. //
  52. // Class: CBitStream
  53. //
  54. // Purpose: Bit Stream
  55. //
  56. // History: 08-Jul-91 KyleP Created.
  57. // 10-Apr-94 SrikantS Added a "Refill" method to invalidate
  58. // the current buffer and reload during
  59. // master merge.
  60. //
  61. //----------------------------------------------------------------------------
  62. class CBitStream
  63. {
  64. public:
  65. __forceinline ULONG GetBits( unsigned cb);
  66. __forceinline ULONG* EndBuf()
  67. {
  68. Win4Assert( _pEndBuf == ( _buffer.Get() + SMARTBUF_PAGE_SIZE_IN_DWORDS ) );
  69. return _pEndBuf;
  70. }
  71. __forceinline void GetOffset ( BitOffset& off );
  72. void GetBytes(BYTE * pb, unsigned cb);
  73. #if CIDBG == 1
  74. virtual void Dump();
  75. unsigned PeekBit();
  76. #endif // CIDBG == 1
  77. void Seek ( const BitOffset& off );
  78. void Refill();
  79. //
  80. // We can remove RefillStream() and FreeStream() once NTFS supports
  81. // sparse file operations on parts of a file when other parts
  82. // of the file are mapped. This probably won't happen any time soon.
  83. //
  84. void RefillStream()
  85. {
  86. if ( !_buffer.isEmpty() )
  87. return;
  88. //
  89. // Re-map the stream if necessary, if unmapped for a shrink from
  90. // front.
  91. //
  92. Win4Assert( _buffer.IsWritable() );
  93. _buffer.Refill( _buffer.PageNum() );
  94. _pCurPos = (ULONG *) ( _oBuffer + (ULONG_PTR) _buffer.Get() );
  95. _pEndBuf = ( _buffer.Get() + SMARTBUF_PAGE_SIZE_IN_DWORDS );
  96. ciDebugOut(( DEB_BITSTM,
  97. "refilled stream '%ws', pCur 0x%x, pBase 0x%x, offset 0x%x, page 0x%x, this 0x%x\n",
  98. _buffer.GetPath(),
  99. _pCurPos,
  100. _buffer.Get(),
  101. _oBuffer,
  102. _buffer.PageNum(),
  103. this ));
  104. _oBuffer = 0;
  105. }
  106. void FreeStream()
  107. {
  108. //
  109. // If the stream is writable, unmap it so we can do a shrink from
  110. // front on the index.
  111. //
  112. if ( _buffer.IsWritable() )
  113. {
  114. if ( !_buffer.isEmpty() )
  115. {
  116. _oBuffer = (ULONG)((ULONG_PTR) _pCurPos - (ULONG_PTR) _buffer.Get());
  117. }
  118. ciDebugOut(( DEB_BITSTM,
  119. "tossing stream '%ws', pcur 0x%x, buf 0x%x, offset 0x%x, page 0x%x\n",
  120. _buffer.GetPath(), _pCurPos, _buffer.Get(), _oBuffer, _buffer.PageNum() ));
  121. _buffer.Free();
  122. _pCurPos = 0;
  123. }
  124. }
  125. #ifdef CIEXTMODE
  126. void CiExtDump(void *ciExtSelf);
  127. #endif
  128. protected:
  129. CBitStream(CPhysStorage& phStorage, CSmartBuffer::EAccessMode mode );
  130. CBitStream(CPhysStorage& phStorage, BOOL fCreate);
  131. CBitStream(CPhysStorage& phStorage, const BitOffset& off,
  132. CSmartBuffer::EAccessMode mode, BOOL fIncrSig = TRUE);
  133. CBitStream(CBitStream & orig);
  134. __forceinline ULONG Position();
  135. void SetPosition(ULONG off);
  136. void NextDword();
  137. void LoadNextPage();
  138. void LoadNewPage();
  139. ULONG IGetBits (unsigned cb);
  140. unsigned _cbitLeftDW; // Bits left in the current DWord.
  141. ULONG * _pCurPos; // Current (DWord) position in buffer.
  142. ULONG * _pEndBuf;
  143. ULONG _oBuffer; // offset when buffer is freed
  144. CSmartBuffer _buffer;
  145. };
  146. //+---------------------------------------------------------------------------
  147. //
  148. // Class: CWBitStream
  149. //
  150. // Purpose: Writable Bit Stream
  151. //
  152. // Interface:
  153. //
  154. // History: 24-Aug-92 BartoszM Created
  155. // 10-Apr-94 SrikantS Added the ability to open
  156. // an existing stream for write
  157. // access during Master Merge.
  158. //
  159. //----------------------------------------------------------------------------
  160. class CWBitStream : public CBitStream
  161. {
  162. public:
  163. CWBitStream ( CPhysStorage& phStorage ): CBitStream ( phStorage, TRUE ) {}
  164. CWBitStream ( CPhysStorage& phStorage, const BitOffset & bitOff, BOOL fIncrSig = TRUE ) :
  165. CBitStream( phStorage, bitOff, CSmartBuffer::eWriteExisting, fIncrSig ) {}
  166. inline void PutBits(ULONG ul, unsigned cb);
  167. void PutBytes(const BYTE * pb, unsigned cb);
  168. void ZeroToEndOfPage();
  169. void InitSignature();
  170. #ifdef CIEXTMODE
  171. void CiExtDump(void *ciExtSelf);
  172. #endif
  173. private:
  174. void NextDword();
  175. void IPutBits(ULONG ul, unsigned cb);
  176. };
  177. //+---------------------------------------------------------------------------
  178. //
  179. // Class: CPBitStream
  180. //
  181. // Purpose: Patch Bit Stream, used for back patching
  182. //
  183. // History: 24-Aug-92 BartoszM Created
  184. //
  185. // Notes: Seek is very cheap, since it doesn't load the page.
  186. // Pages are loaded on demand when writing.
  187. //
  188. //----------------------------------------------------------------------------
  189. class CPBitStream : public CBitStream
  190. {
  191. public:
  192. CPBitStream ( CPhysStorage& phStorage );
  193. void OverwriteBits(ULONG ul, unsigned cb);
  194. __forceinline void SkipBits ( unsigned delta )
  195. {
  196. _bitOff += delta;
  197. Win4Assert( _bitOff.Offset() < SMARTBUF_PAGE_SIZE_IN_BITS );
  198. }
  199. __forceinline void Seek ( const BitOffset& off )
  200. {
  201. _bitOff = off;
  202. Win4Assert( _bitOff.Offset() < SMARTBUF_PAGE_SIZE_IN_BITS );
  203. }
  204. __forceinline void GetOffset ( BitOffset& off ) {
  205. RtlCopyMemory( &off, &_bitOff, sizeof BitOffset );
  206. }
  207. #if CIDBG == 1
  208. unsigned PeekBit();
  209. virtual void Dump();
  210. #endif // CIDBG == 1
  211. #ifdef CIEXTMODE
  212. void CiExtDump(void *ciExtSelf);
  213. #endif
  214. private:
  215. void IOverwriteBits(ULONG ul, unsigned cb);
  216. BitOffset _bitOff;
  217. };
  218. //+---------------------------------------------------------------------------
  219. //
  220. // Class: CRBitStream
  221. //
  222. // Purpose: Readable Bit Stream
  223. //
  224. // History: 24-Aug-92 BartoszM Created
  225. //
  226. //----------------------------------------------------------------------------
  227. class CRBitStream : public CBitStream
  228. {
  229. public:
  230. CRBitStream ( CPhysStorage& phStorage ): CBitStream ( phStorage, FALSE ) {}
  231. CRBitStream ( CPhysStorage& phStorage, const BitOffset& off )
  232. : CBitStream ( phStorage, off, CSmartBuffer::eReadExisting ) {}
  233. };
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Member: CBitStream::GetOffset, public
  237. //
  238. // Synopsis: Returns bit offset within the index.
  239. //
  240. // Arguments: [off] -- (out) bit offset
  241. //
  242. // History: 28-Aug-92 BartoszM Created.
  243. //
  244. //----------------------------------------------------------------------------
  245. __forceinline void CBitStream::GetOffset ( BitOffset& off )
  246. {
  247. off.Init( _buffer.PageNum(), Position() );
  248. }
  249. //+---------------------------------------------------------------------------
  250. //
  251. // Member: CBitStream::Position, private
  252. //
  253. // Synopsis: Returns bit position within current page
  254. //
  255. // History: 28-Aug-92 BartoszM Created.
  256. //
  257. //----------------------------------------------------------------------------
  258. __forceinline ULONG CBitStream::Position()
  259. {
  260. return CiPtrToUlong(_pCurPos - _buffer.Get() + 1) * ULONG_BITS - _cbitLeftDW;
  261. }
  262. //+---------------------------------------------------------------------------
  263. //
  264. // Member: CBitStream::NextDword, private
  265. //
  266. // Synopsis: Increments current dword pointer,
  267. // loads next page if necessary.
  268. //
  269. // History: 28-Aug-92 BartoszM Created.
  270. //
  271. //----------------------------------------------------------------------------
  272. __forceinline void CBitStream::NextDword()
  273. {
  274. _pCurPos++;
  275. _cbitLeftDW = ULONG_BITS;
  276. if (_pCurPos >= EndBuf())
  277. {
  278. LoadNextPage();
  279. }
  280. }
  281. //+---------------------------------------------------------------------------
  282. //
  283. // Member: CWBitStream::NextDword, private
  284. //
  285. // Synopsis: Increments current dword pointer,
  286. // loads new page if necessary.
  287. //
  288. // History: 28-Aug-92 BartoszM Created.
  289. //
  290. //----------------------------------------------------------------------------
  291. __forceinline void CWBitStream::NextDword()
  292. {
  293. _pCurPos++;
  294. _cbitLeftDW = ULONG_BITS;
  295. if (_pCurPos >= EndBuf())
  296. {
  297. LoadNewPage();
  298. }
  299. }
  300. //+---------------------------------------------------------------------------
  301. //
  302. // Member: CWBitStream::PutBits, public
  303. //
  304. // Synopsis: Store bits in the buffer.
  305. //
  306. // Effects: Store the [cb] low bits in [ul] beginning at the 'bit-cursor'
  307. //
  308. // Arguments: [ul] -- A DWord containing data to store.
  309. //
  310. // [cb] -- The number of bits to store.
  311. //
  312. // History: 08-Jul-91 KyleP Created.
  313. //
  314. // Notes: Bits are stored 'big-endian'.
  315. //
  316. //----------------------------------------------------------------------------
  317. __forceinline void CWBitStream::PutBits(ULONG ul, unsigned cb)
  318. {
  319. // ciDebugOut (( DEB_BITSTM , "PutBits %d\n", cb ));
  320. Win4Assert(cb != 0 && cb <= ULONG_BITS);
  321. //
  322. // The ULONG we're storing must be zero-filled at the top.
  323. //
  324. Win4Assert( (cb == ULONG_BITS) || ( (ul >> cb) == 0 ) );
  325. //
  326. // The easy case is the one where all the data fits in 1 dword.
  327. //
  328. if (cb <= _cbitLeftDW)
  329. {
  330. Win4Assert ( _pCurPos < EndBuf() );
  331. _cbitLeftDW -= cb;
  332. *_pCurPos |= (ul << _cbitLeftDW);
  333. }
  334. else
  335. {
  336. IPutBits(ul, cb);
  337. }
  338. }
  339. //+---------------------------------------------------------------------------
  340. //
  341. // Member: CBitStream::GetBits, public
  342. //
  343. // Synopsis: Retrieve bits from the buffer.
  344. //
  345. // Arguments: [cb] -- Count of bits to retrieve.
  346. //
  347. // History: 12-Jul-91 KyleP Created.
  348. //
  349. //----------------------------------------------------------------------------
  350. __forceinline ULONG CBitStream::GetBits(unsigned cb)
  351. {
  352. // ciDebugOut (( DEB_BITSTM , "GetBits %d\n", cb ));
  353. Win4Assert(cb != 0 && cb <= ULONG_BITS);
  354. //
  355. // The easy case is when the data can be extracted from the
  356. // current dword.
  357. //
  358. if (cb <= _cbitLeftDW)
  359. {
  360. ULONG mask = 0xFFFFFFFF;
  361. if (cb != ULONG_BITS)
  362. {
  363. mask = ~(mask << cb);
  364. }
  365. _cbitLeftDW -= cb;
  366. return (*_pCurPos >> _cbitLeftDW) & mask;
  367. }
  368. else
  369. {
  370. return IGetBits( cb );
  371. }
  372. }