479 lines
12 KiB
C++
479 lines
12 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 );
|
||
|
}
|
||
|
|