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

//+---------------------------------------------------------------------------
//
// 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 );
}