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.

478 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1997.
  5. //
  6. // File: COMPRESS.HXX
  7. //
  8. // Contents: Compressor/Decompressor of data
  9. //
  10. // Classes: CCompress, CDecompress
  11. //
  12. // History: 12-Jun-91 BartoszM Created
  13. // 20-Jun-91 reviewed
  14. // 07-Aug-91 BartoszM Introduced Blocks
  15. // 28-May-92 KyleP Added compression
  16. //
  17. //----------------------------------------------------------------------------
  18. #pragma once
  19. #include <pageman.hxx>
  20. const USHORT offInvalid = 0xffff;
  21. const ULONG cbInitialBlock = 8192;
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Class: CBlock
  25. //
  26. // Purpose: Block of data in sort chunk
  27. //
  28. // History: 7-Aug-91 BartoszM Created
  29. //
  30. //----------------------------------------------------------------------------
  31. class CBlock
  32. {
  33. public:
  34. CBlock() :
  35. _pNext(0),
  36. _fCompressed(FALSE),
  37. _cbCompressed(0),
  38. _cbInUse(0),
  39. _offFirstKey(offInvalid)
  40. {
  41. _pData = new BYTE[ cbInitialBlock ];
  42. }
  43. ~CBlock() { delete [] _pData; }
  44. void GetFirstKey ( CKeyBuf & key );
  45. void CompressList();
  46. void Compress();
  47. void DeCompress();
  48. BYTE * Buffer() { return _pData; }
  49. USHORT InUse() { return _cbInUse; }
  50. #ifdef CIEXTMODE
  51. void CiExtDump(void *ciExtSelf);
  52. #endif
  53. CBlock * _pNext;
  54. BYTE * _pData; // the actual data
  55. USHORT _fCompressed; // whether _pData is RtlCompressed
  56. USHORT _cbCompressed; // size when compressed
  57. USHORT _cbInUse; // size of actual uncompressed data in buffer
  58. USHORT _offFirstKey; // offset to first key in buffer
  59. };
  60. //+---------------------------------------------------------------------------
  61. //
  62. // Class: CCompress
  63. //
  64. // Purpose: Compress data into a series of blocks
  65. //
  66. // History: 12-Jun-91 BartoszM Created
  67. // 13-May-92 KyleP Added compression.
  68. //
  69. // Notes: The following compression schemes are used:
  70. // o Prefix compressed keys
  71. // o 1 Byte Wid/WidCount (max 255 Wid/compressor)
  72. // o 1 byte/2 byte/4 byte occurrence deltas.
  73. //
  74. //----------------------------------------------------------------------------
  75. class CCompress
  76. {
  77. public:
  78. CCompress();
  79. ~CCompress();
  80. CBlock * GetFirstBlock();
  81. void PutKey ( unsigned cb, const BYTE* buf, PROPID pid );
  82. void PutWid ( WORKID wid );
  83. void PutOcc ( OCCURRENCE occ );
  84. BOOL SameWid ( WORKID wid ) const
  85. { return ( wid == _lastWid ); }
  86. BOOL SamePid ( PROPID pid ) const
  87. { return ( pid == _lastKey.Pid() ); }
  88. inline BOOL SameKey ( unsigned cb, const BYTE * buf ) const;
  89. unsigned KeyBlockCount () { return _cKeyBlock; }
  90. #ifdef CIEXTMODE
  91. void CiExtDump(void *ciExtSelf);
  92. #endif
  93. protected:
  94. inline BOOL KeyWillFit( unsigned cb ) const;
  95. inline BOOL WidAndOccCountWillFit() const;
  96. inline BOOL WidWillFit() const;
  97. inline BOOL OccWillFit( OCCURRENCE occDelta ) const;
  98. inline BOOL OccCountWillFit() const;
  99. //
  100. // The Internal put methods are used as the building blocks for
  101. // PutKey/Wid/Occ in both CCompress and COneWidCompress.
  102. //
  103. void IPutKey( unsigned cb, const BYTE * buf, PROPID pid );
  104. void IPutWid( WORKID wid );
  105. void IAllocWidCount();
  106. void IPutWidCount();
  107. void IPutOcc( OCCURRENCE occ );
  108. void IAllocOccCount();
  109. void IPutOccCount();
  110. void AllocNewBlock ();
  111. void BackPatch ( unsigned off )
  112. {
  113. _block->_offFirstKey = (WORD)off;
  114. _cKeyBlock++;
  115. }
  116. WORKID _lastWid;
  117. OCCURRENCE _lastOcc;
  118. // pointers for back-patching the counts
  119. BYTE * _pWidCount;
  120. BYTE * _pOccCount;
  121. unsigned _widCount;
  122. unsigned _occCount;
  123. CBlock * _block; // current block
  124. unsigned _cKeyBlock; // count of blocks with keys
  125. BYTE* _buf; // current buffer to write to
  126. BYTE* _cur; // current position in buffer
  127. //
  128. // For prefix compression.
  129. //
  130. CKeyBuf _lastKey;
  131. };
  132. //+---------------------------------------------------------------------------
  133. //
  134. // Class: COneWidCompress
  135. //
  136. // Purpose: Compress data for single workid into a series of blocks.
  137. //
  138. // History: 26-May-92 KyleP Created
  139. //
  140. // Notes: In addition to the compression schemes used in CCompress
  141. // no WorkId or WorkId count is stored at all.
  142. //
  143. //----------------------------------------------------------------------------
  144. class COneWidCompress : public CCompress
  145. {
  146. public:
  147. void PutKey ( unsigned cb, const BYTE* buf, PROPID pid );
  148. #if CIDBG == 1
  149. void PutWid ( WORKID wid );
  150. #endif // CIDBG == 1
  151. void PutOcc ( OCCURRENCE occ );
  152. };
  153. //+---------------------------------------------------------------------------
  154. //
  155. // Class: CDecompress
  156. //
  157. // Purpose: Decompress data
  158. //
  159. // History: 12-Jun-91 BartoszM Created
  160. // 28-May-92 KyleP Added compression
  161. //
  162. // Notes: CDecompress uncompresses buffers compressed with CCompress.
  163. //
  164. //----------------------------------------------------------------------------
  165. class CDecompress
  166. {
  167. public:
  168. inline const CKeyBuf* GetKey() const;
  169. inline WORKID WorkId() const;
  170. inline OCCURRENCE Occurrence() const;
  171. //
  172. // Init and GetNext* will be over-ridden in COneWidDecompress.
  173. //
  174. void Init (CBlock* block );
  175. const CKeyBuf* GetNextKey();
  176. WORKID NextWorkId();
  177. OCCURRENCE NextOccurrence();
  178. ULONG WorkIdCount() { return _widCount; }
  179. ULONG OccurrenceCount() { return _occCount; }
  180. void RatioFinished ( ULONG& denom, ULONG& num );
  181. #ifdef CIEXTMODE
  182. void CiExtDump(void *ciExtSelf);
  183. #endif
  184. protected:
  185. //
  186. // The Load methods are used as building blocks for both CDecompress
  187. // and COneWidDecompress.
  188. //
  189. BOOL LoadNextBlock ();
  190. void LoadKey();
  191. void LoadWidCount();
  192. void LoadWid();
  193. void LoadOccCount();
  194. void LoadOcc();
  195. BOOL KeyExists() const
  196. { return _curKey.Count() != 0; }
  197. BOOL EndBlock() const
  198. { return ( (unsigned)(_cur - _buf) >= _cbInUse ); }
  199. CBlock* _block; // current block
  200. unsigned _cbInUse; // actual number of bytes in buffer
  201. const BYTE* _buf; // buffer to read from
  202. const BYTE* _cur; // current position within buffer
  203. BYTE _widCount; // work id count
  204. unsigned _occCount; // occurrence count
  205. unsigned _widCountLeft; // work ids left
  206. unsigned _occCountLeft; // occurrences left
  207. CKeyBuf _curKey; // Key under the cursor
  208. WORKID _curWid; // WorkId under the cursor
  209. OCCURRENCE _curOcc; // Occurrence under the cursor
  210. };
  211. //+---------------------------------------------------------------------------
  212. //
  213. // Class: COneWidDecompress
  214. //
  215. // Purpose: Decompress data
  216. //
  217. // History: 28-May-92 KyleP Created
  218. //
  219. // Notes: COneWidDecompress uncompresses buffers compressed
  220. // with COneWidCompress.
  221. //
  222. //----------------------------------------------------------------------------
  223. class COneWidDecompress : public CDecompress
  224. {
  225. public:
  226. void Init( CBlock* block );
  227. const CKeyBuf* GetNextKey();
  228. WORKID NextWorkId();
  229. OCCURRENCE NextOccurrence();
  230. };
  231. //+---------------------------------------------------------------------------
  232. //
  233. // Member: CCompress::SameKey, public
  234. //
  235. // Synopsis: compare argument with last key
  236. //
  237. // Arguments: [cb] - size of key
  238. // [buf] - key buffer
  239. //
  240. // History: 12-Jun-91 BartoszM Created
  241. //
  242. //----------------------------------------------------------------------------
  243. inline BOOL CCompress::SameKey ( unsigned cb, const BYTE * buf ) const
  244. {
  245. if ( cb == _lastKey.Count() )
  246. return ( memcmp ( buf, _lastKey.GetBuf(), cb ) == 0 );
  247. else
  248. return FALSE;
  249. }
  250. //+---------------------------------------------------------------------------
  251. //
  252. // Member: CCompress::KeyWillFit, private
  253. //
  254. // Synopsis: check if the key will fit into current buffer
  255. //
  256. // Arguments: [cb] -- byte size of the key suffix
  257. //
  258. // History: 07-Aug-91 BartoszM Created
  259. // 28-May-92 KyleP Adjusted for compression
  260. //
  261. //----------------------------------------------------------------------------
  262. inline BOOL CCompress::KeyWillFit ( unsigned cb ) const
  263. {
  264. // This is an absolutely worst-case estimate. Most keys will be smaller.
  265. // Note: This also allocates room for the wid count, which is only needed
  266. // for the many-wid compressor.
  267. unsigned need = cb + // Suffix
  268. sizeof(BYTE) + // Flags field
  269. sizeof(BYTE) + // Prefix size
  270. sizeof(BYTE) + // Suffix size
  271. sizeof(PROPID) + sizeof(BYTE) + // Property ID (worst case)
  272. sizeof(BYTE); // WID Count
  273. return ( (_cur + need) < (_buf + cbInitialBlock ) );
  274. }
  275. //+---------------------------------------------------------------------------
  276. //
  277. // Member: CCompress::OccCountWillFit, private
  278. //
  279. // Synopsis: check if the occurrence count will fit into current buffer
  280. //
  281. // History: 06-Dec-99 dlee Created
  282. //
  283. //----------------------------------------------------------------------------
  284. inline BOOL CCompress::OccCountWillFit () const
  285. {
  286. unsigned need = sizeof(unsigned);
  287. return ( _cur + need < _buf + cbInitialBlock );
  288. }
  289. //+---------------------------------------------------------------------------
  290. //
  291. // Member: CCompress::WidAndOccCountWillFit, private
  292. //
  293. // Synopsis: check if wid and occ count will fit into current buffer
  294. //
  295. // History: 07-Aug-91 BartoszM Created
  296. // 28-May-92 KyleP Adjusted for compression
  297. //
  298. //----------------------------------------------------------------------------
  299. inline BOOL CCompress::WidAndOccCountWillFit () const
  300. {
  301. // wid + occCount
  302. // Note: this isn't called for single wid compressors.
  303. unsigned need = sizeof(BYTE) + sizeof(unsigned);
  304. return ( _cur + need < _buf + cbInitialBlock );
  305. }
  306. //+---------------------------------------------------------------------------
  307. //
  308. // Member: CCompress::WidWillFit, private
  309. //
  310. // Synopsis: check if wid will fit into current buffer
  311. //
  312. // History: 06-Dec-99 dlee Created
  313. //
  314. //----------------------------------------------------------------------------
  315. inline BOOL CCompress::WidWillFit () const
  316. {
  317. // wid
  318. unsigned need = sizeof(BYTE);
  319. return ( _cur + need < _buf + cbInitialBlock );
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Member: CCompress::OccWillFit, private
  324. //
  325. // Synopsis: check occ will fit into current buffer
  326. //
  327. // History: 07-Aug-91 BartoszM Created
  328. // 28-May-92 KyleP Adjusted for compression
  329. //
  330. //----------------------------------------------------------------------------
  331. inline BOOL CCompress::OccWillFit( OCCURRENCE occDelta ) const
  332. {
  333. unsigned next;
  334. if ( occDelta <= (1 << 8) - 1 )
  335. next = 1;
  336. else if ( occDelta <= (1 << 16) - 1 )
  337. next = 3;
  338. else
  339. next = 7;
  340. return ( _cur + next < _buf + cbInitialBlock );
  341. }
  342. //+---------------------------------------------------------------------------
  343. //
  344. // Member: CDeCompress::GetKey, public
  345. //
  346. // Synopsis: return current key
  347. //
  348. // History: 12-Jun-91 BartoszM Created
  349. //
  350. //----------------------------------------------------------------------------
  351. inline const CKeyBuf * CDecompress::GetKey() const
  352. {
  353. if( KeyExists() )
  354. return &_curKey;
  355. else
  356. return 0;
  357. }
  358. //+---------------------------------------------------------------------------
  359. //
  360. // Member: CDeCompress::WorkId, public
  361. //
  362. // Synopsis: return current work id
  363. //
  364. // History: 12-Jun-91 BartoszM Created
  365. //
  366. //----------------------------------------------------------------------------
  367. inline WORKID CDecompress::WorkId() const
  368. {
  369. ciAssert ( KeyExists() );
  370. return( _curWid );
  371. }
  372. //+---------------------------------------------------------------------------
  373. //
  374. // Member: CDeCompress::Occurrence, public
  375. //
  376. // Synopsis: return current occurrence
  377. //
  378. // History: 12-Jun-91 BartoszM Created
  379. //
  380. //----------------------------------------------------------------------------
  381. inline OCCURRENCE CDecompress::Occurrence() const
  382. {
  383. ciAssert ( KeyExists() );
  384. return( _curOcc );
  385. }