|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 1997.
//
// File: COMPRESS.HXX
//
// Contents: Compressor/Decompressor of data
//
// Classes: CCompress, CDecompress
//
// History: 12-Jun-91 BartoszM Created
// 20-Jun-91 reviewed
// 07-Aug-91 BartoszM Introduced Blocks
// 28-May-92 KyleP Added compression
//
//----------------------------------------------------------------------------
#pragma once
#include <pageman.hxx>
const USHORT offInvalid = 0xffff;
const ULONG cbInitialBlock = 8192;
//+---------------------------------------------------------------------------
//
// Class: CBlock
//
// Purpose: Block of data in sort chunk
//
// History: 7-Aug-91 BartoszM Created
//
//----------------------------------------------------------------------------
class CBlock { public: CBlock() : _pNext(0), _fCompressed(FALSE), _cbCompressed(0), _cbInUse(0), _offFirstKey(offInvalid) { _pData = new BYTE[ cbInitialBlock ]; }
~CBlock() { delete [] _pData; }
void GetFirstKey ( CKeyBuf & key ); void CompressList(); void Compress(); void DeCompress(); BYTE * Buffer() { return _pData; }
USHORT InUse() { return _cbInUse; }
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf); #endif
CBlock * _pNext; BYTE * _pData; // the actual data
USHORT _fCompressed; // whether _pData is RtlCompressed
USHORT _cbCompressed; // size when compressed
USHORT _cbInUse; // size of actual uncompressed data in buffer
USHORT _offFirstKey; // offset to first key in buffer
};
//+---------------------------------------------------------------------------
//
// Class: CCompress
//
// Purpose: Compress data into a series of blocks
//
// History: 12-Jun-91 BartoszM Created
// 13-May-92 KyleP Added compression.
//
// Notes: The following compression schemes are used:
// o Prefix compressed keys
// o 1 Byte Wid/WidCount (max 255 Wid/compressor)
// o 1 byte/2 byte/4 byte occurrence deltas.
//
//----------------------------------------------------------------------------
class CCompress { public:
CCompress();
~CCompress();
CBlock * GetFirstBlock();
void PutKey ( unsigned cb, const BYTE* buf, PROPID pid );
void PutWid ( WORKID wid );
void PutOcc ( OCCURRENCE occ );
BOOL SameWid ( WORKID wid ) const { return ( wid == _lastWid ); }
BOOL SamePid ( PROPID pid ) const { return ( pid == _lastKey.Pid() ); }
inline BOOL SameKey ( unsigned cb, const BYTE * buf ) const;
unsigned KeyBlockCount () { return _cKeyBlock; }
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf); #endif
protected:
inline BOOL KeyWillFit( unsigned cb ) const; inline BOOL WidAndOccCountWillFit() const; inline BOOL WidWillFit() const; inline BOOL OccWillFit( OCCURRENCE occDelta ) const; inline BOOL OccCountWillFit() const;
//
// The Internal put methods are used as the building blocks for
// PutKey/Wid/Occ in both CCompress and COneWidCompress.
//
void IPutKey( unsigned cb, const BYTE * buf, PROPID pid );
void IPutWid( WORKID wid ); void IAllocWidCount(); void IPutWidCount();
void IPutOcc( OCCURRENCE occ ); void IAllocOccCount(); void IPutOccCount();
void AllocNewBlock (); void BackPatch ( unsigned off ) { _block->_offFirstKey = (WORD)off; _cKeyBlock++; }
WORKID _lastWid; OCCURRENCE _lastOcc;
// pointers for back-patching the counts
BYTE * _pWidCount; BYTE * _pOccCount;
unsigned _widCount; unsigned _occCount;
CBlock * _block; // current block
unsigned _cKeyBlock; // count of blocks with keys
BYTE* _buf; // current buffer to write to
BYTE* _cur; // current position in buffer
//
// For prefix compression.
//
CKeyBuf _lastKey; };
//+---------------------------------------------------------------------------
//
// Class: COneWidCompress
//
// Purpose: Compress data for single workid into a series of blocks.
//
// History: 26-May-92 KyleP Created
//
// Notes: In addition to the compression schemes used in CCompress
// no WorkId or WorkId count is stored at all.
//
//----------------------------------------------------------------------------
class COneWidCompress : public CCompress { public:
void PutKey ( unsigned cb, const BYTE* buf, PROPID pid );
#if CIDBG == 1
void PutWid ( WORKID wid ); #endif // CIDBG == 1
void PutOcc ( OCCURRENCE occ ); };
//+---------------------------------------------------------------------------
//
// Class: CDecompress
//
// Purpose: Decompress data
//
// History: 12-Jun-91 BartoszM Created
// 28-May-92 KyleP Added compression
//
// Notes: CDecompress uncompresses buffers compressed with CCompress.
//
//----------------------------------------------------------------------------
class CDecompress { public:
inline const CKeyBuf* GetKey() const; inline WORKID WorkId() const; inline OCCURRENCE Occurrence() const;
//
// Init and GetNext* will be over-ridden in COneWidDecompress.
//
void Init (CBlock* block );
const CKeyBuf* GetNextKey(); WORKID NextWorkId(); OCCURRENCE NextOccurrence();
ULONG WorkIdCount() { return _widCount; }
ULONG OccurrenceCount() { return _occCount; } void RatioFinished ( ULONG& denom, ULONG& num );
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf); #endif
protected:
//
// The Load methods are used as building blocks for both CDecompress
// and COneWidDecompress.
//
BOOL LoadNextBlock ();
void LoadKey(); void LoadWidCount(); void LoadWid(); void LoadOccCount(); void LoadOcc();
BOOL KeyExists() const { return _curKey.Count() != 0; } BOOL EndBlock() const { return ( (unsigned)(_cur - _buf) >= _cbInUse ); }
CBlock* _block; // current block
unsigned _cbInUse; // actual number of bytes in buffer
const BYTE* _buf; // buffer to read from
const BYTE* _cur; // current position within buffer
BYTE _widCount; // work id count
unsigned _occCount; // occurrence count
unsigned _widCountLeft; // work ids left
unsigned _occCountLeft; // occurrences left
CKeyBuf _curKey; // Key under the cursor
WORKID _curWid; // WorkId under the cursor
OCCURRENCE _curOcc; // Occurrence under the cursor
};
//+---------------------------------------------------------------------------
//
// Class: COneWidDecompress
//
// Purpose: Decompress data
//
// History: 28-May-92 KyleP Created
//
// Notes: COneWidDecompress uncompresses buffers compressed
// with COneWidCompress.
//
//----------------------------------------------------------------------------
class COneWidDecompress : public CDecompress { public:
void Init( CBlock* block );
const CKeyBuf* GetNextKey(); WORKID NextWorkId(); OCCURRENCE NextOccurrence(); };
//+---------------------------------------------------------------------------
//
// Member: CCompress::SameKey, public
//
// Synopsis: compare argument with last key
//
// Arguments: [cb] - size of key
// [buf] - key buffer
//
// History: 12-Jun-91 BartoszM Created
//
//----------------------------------------------------------------------------
inline BOOL CCompress::SameKey ( unsigned cb, const BYTE * buf ) const { if ( cb == _lastKey.Count() ) return ( memcmp ( buf, _lastKey.GetBuf(), cb ) == 0 ); else return FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CCompress::KeyWillFit, private
//
// Synopsis: check if the key will fit into current buffer
//
// Arguments: [cb] -- byte size of the key suffix
//
// History: 07-Aug-91 BartoszM Created
// 28-May-92 KyleP Adjusted for compression
//
//----------------------------------------------------------------------------
inline BOOL CCompress::KeyWillFit ( unsigned cb ) const { // This is an absolutely worst-case estimate. Most keys will be smaller.
// Note: This also allocates room for the wid count, which is only needed
// for the many-wid compressor.
unsigned need = cb + // Suffix
sizeof(BYTE) + // Flags field
sizeof(BYTE) + // Prefix size
sizeof(BYTE) + // Suffix size
sizeof(PROPID) + sizeof(BYTE) + // Property ID (worst case)
sizeof(BYTE); // WID Count
return ( (_cur + need) < (_buf + cbInitialBlock ) ); }
//+---------------------------------------------------------------------------
//
// Member: CCompress::OccCountWillFit, private
//
// Synopsis: check if the occurrence count will fit into current buffer
//
// History: 06-Dec-99 dlee Created
//
//----------------------------------------------------------------------------
inline BOOL CCompress::OccCountWillFit () const { unsigned need = sizeof(unsigned); return ( _cur + need < _buf + cbInitialBlock ); }
//+---------------------------------------------------------------------------
//
// Member: CCompress::WidAndOccCountWillFit, private
//
// Synopsis: check if wid and occ count will fit into current buffer
//
// History: 07-Aug-91 BartoszM Created
// 28-May-92 KyleP Adjusted for compression
//
//----------------------------------------------------------------------------
inline BOOL CCompress::WidAndOccCountWillFit () const { // wid + occCount
// Note: this isn't called for single wid compressors.
unsigned need = sizeof(BYTE) + sizeof(unsigned); return ( _cur + need < _buf + cbInitialBlock ); }
//+---------------------------------------------------------------------------
//
// Member: CCompress::WidWillFit, private
//
// Synopsis: check if wid will fit into current buffer
//
// History: 06-Dec-99 dlee Created
//
//----------------------------------------------------------------------------
inline BOOL CCompress::WidWillFit () const { // wid
unsigned need = sizeof(BYTE); return ( _cur + need < _buf + cbInitialBlock ); }
//+---------------------------------------------------------------------------
//
// Member: CCompress::OccWillFit, private
//
// Synopsis: check occ will fit into current buffer
//
// History: 07-Aug-91 BartoszM Created
// 28-May-92 KyleP Adjusted for compression
//
//----------------------------------------------------------------------------
inline BOOL CCompress::OccWillFit( OCCURRENCE occDelta ) const { unsigned next;
if ( occDelta <= (1 << 8) - 1 ) next = 1; else if ( occDelta <= (1 << 16) - 1 ) next = 3; else next = 7;
return ( _cur + next < _buf + cbInitialBlock ); }
//+---------------------------------------------------------------------------
//
// Member: CDeCompress::GetKey, public
//
// Synopsis: return current key
//
// History: 12-Jun-91 BartoszM Created
//
//----------------------------------------------------------------------------
inline const CKeyBuf * CDecompress::GetKey() const { if( KeyExists() ) return &_curKey; else return 0; }
//+---------------------------------------------------------------------------
//
// Member: CDeCompress::WorkId, public
//
// Synopsis: return current work id
//
// History: 12-Jun-91 BartoszM Created
//
//----------------------------------------------------------------------------
inline WORKID CDecompress::WorkId() const { ciAssert ( KeyExists() );
return( _curWid ); }
//+---------------------------------------------------------------------------
//
// Member: CDeCompress::Occurrence, public
//
// Synopsis: return current occurrence
//
// History: 12-Jun-91 BartoszM Created
//
//----------------------------------------------------------------------------
inline OCCURRENCE CDecompress::Occurrence() const { ciAssert ( KeyExists() ); return( _curOcc ); }
|