470 lines
12 KiB
C++
470 lines
12 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1991 - 2000.
|
||
|
//
|
||
|
// File: BITSTM.hxx
|
||
|
//
|
||
|
// Contents: 'Bit streams'
|
||
|
//
|
||
|
// Classes: CBitStream, CWBitStream, CPBitStream, CRBitStream
|
||
|
//
|
||
|
// History: 03-Jul-91 KyleP Created
|
||
|
// 24-Aug-92 BartoszM Rewrote it
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <bitoff.hxx>
|
||
|
#include "physidx.hxx"
|
||
|
#include <ci64.hxx>
|
||
|
|
||
|
class CSmartBuffer
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
enum EAccessMode { eReadExisting, eWriteExisting };
|
||
|
|
||
|
CSmartBuffer ( CPhysStorage& phStorage, EAccessMode mode );
|
||
|
CSmartBuffer ( CPhysStorage& phStorage, BOOL fCreate );
|
||
|
CSmartBuffer ( CPhysStorage& phStorage, ULONG numPage, EAccessMode mode, BOOL fIncrSig = TRUE );
|
||
|
CSmartBuffer ( CSmartBuffer& buf, ULONG numPage );
|
||
|
~CSmartBuffer ();
|
||
|
|
||
|
ULONG PageNum() { return _numPage; }
|
||
|
__forceinline ULONG* Get() { return _pBuffer + 1; }
|
||
|
BOOL isEmpty() { return _pBuffer == 0; }
|
||
|
|
||
|
void Refill ( ULONG numPage );
|
||
|
ULONG* Next();
|
||
|
ULONG* NextNew();
|
||
|
|
||
|
void Free();
|
||
|
|
||
|
BOOL IsWritable() { return _phStorage.IsWritable(); }
|
||
|
|
||
|
WCHAR const * GetPath() { return _phStorage.GetPath(); }
|
||
|
|
||
|
void InitSignature();
|
||
|
|
||
|
#ifdef CIEXTMODE
|
||
|
void CiExtDump(void *ciExtSelf);
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
|
||
|
void CheckCorruption();
|
||
|
void IncrementSig();
|
||
|
|
||
|
CPhysStorage& _phStorage; // Source of pages
|
||
|
ULONG _numPage; // current page number
|
||
|
ULONG * _pBuffer; // Beginning of buffer.
|
||
|
BOOL _fWritable; // Access mode for existing buffers.
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CBitStream
|
||
|
//
|
||
|
// Purpose: Bit Stream
|
||
|
//
|
||
|
// History: 08-Jul-91 KyleP Created.
|
||
|
// 10-Apr-94 SrikantS Added a "Refill" method to invalidate
|
||
|
// the current buffer and reload during
|
||
|
// master merge.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CBitStream
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
__forceinline ULONG GetBits( unsigned cb);
|
||
|
|
||
|
__forceinline ULONG* EndBuf()
|
||
|
{
|
||
|
Win4Assert( _pEndBuf == ( _buffer.Get() + SMARTBUF_PAGE_SIZE_IN_DWORDS ) );
|
||
|
return _pEndBuf;
|
||
|
}
|
||
|
|
||
|
__forceinline void GetOffset ( BitOffset& off );
|
||
|
|
||
|
void GetBytes(BYTE * pb, unsigned cb);
|
||
|
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
virtual void Dump();
|
||
|
unsigned PeekBit();
|
||
|
#endif // CIDBG == 1
|
||
|
|
||
|
void Seek ( const BitOffset& off );
|
||
|
|
||
|
void Refill();
|
||
|
|
||
|
//
|
||
|
// We can remove RefillStream() and FreeStream() once NTFS supports
|
||
|
// sparse file operations on parts of a file when other parts
|
||
|
// of the file are mapped. This probably won't happen any time soon.
|
||
|
//
|
||
|
|
||
|
void RefillStream()
|
||
|
{
|
||
|
if ( !_buffer.isEmpty() )
|
||
|
return;
|
||
|
|
||
|
//
|
||
|
// Re-map the stream if necessary, if unmapped for a shrink from
|
||
|
// front.
|
||
|
//
|
||
|
|
||
|
Win4Assert( _buffer.IsWritable() );
|
||
|
|
||
|
_buffer.Refill( _buffer.PageNum() );
|
||
|
_pCurPos = (ULONG *) ( _oBuffer + (ULONG_PTR) _buffer.Get() );
|
||
|
_pEndBuf = ( _buffer.Get() + SMARTBUF_PAGE_SIZE_IN_DWORDS );
|
||
|
|
||
|
ciDebugOut(( DEB_BITSTM,
|
||
|
"refilled stream '%ws', pCur 0x%x, pBase 0x%x, offset 0x%x, page 0x%x, this 0x%x\n",
|
||
|
_buffer.GetPath(),
|
||
|
_pCurPos,
|
||
|
_buffer.Get(),
|
||
|
_oBuffer,
|
||
|
_buffer.PageNum(),
|
||
|
this ));
|
||
|
|
||
|
_oBuffer = 0;
|
||
|
}
|
||
|
|
||
|
void FreeStream()
|
||
|
{
|
||
|
//
|
||
|
// If the stream is writable, unmap it so we can do a shrink from
|
||
|
// front on the index.
|
||
|
//
|
||
|
|
||
|
if ( _buffer.IsWritable() )
|
||
|
{
|
||
|
if ( !_buffer.isEmpty() )
|
||
|
{
|
||
|
_oBuffer = (ULONG)((ULONG_PTR) _pCurPos - (ULONG_PTR) _buffer.Get());
|
||
|
}
|
||
|
|
||
|
ciDebugOut(( DEB_BITSTM,
|
||
|
"tossing stream '%ws', pcur 0x%x, buf 0x%x, offset 0x%x, page 0x%x\n",
|
||
|
_buffer.GetPath(), _pCurPos, _buffer.Get(), _oBuffer, _buffer.PageNum() ));
|
||
|
|
||
|
_buffer.Free();
|
||
|
_pCurPos = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef CIEXTMODE
|
||
|
void CiExtDump(void *ciExtSelf);
|
||
|
#endif
|
||
|
|
||
|
protected:
|
||
|
|
||
|
CBitStream(CPhysStorage& phStorage, CSmartBuffer::EAccessMode mode );
|
||
|
|
||
|
CBitStream(CPhysStorage& phStorage, BOOL fCreate);
|
||
|
|
||
|
CBitStream(CPhysStorage& phStorage, const BitOffset& off,
|
||
|
CSmartBuffer::EAccessMode mode, BOOL fIncrSig = TRUE);
|
||
|
|
||
|
CBitStream(CBitStream & orig);
|
||
|
|
||
|
__forceinline ULONG Position();
|
||
|
|
||
|
void SetPosition(ULONG off);
|
||
|
|
||
|
void NextDword();
|
||
|
|
||
|
void LoadNextPage();
|
||
|
|
||
|
void LoadNewPage();
|
||
|
|
||
|
ULONG IGetBits (unsigned cb);
|
||
|
|
||
|
unsigned _cbitLeftDW; // Bits left in the current DWord.
|
||
|
ULONG * _pCurPos; // Current (DWord) position in buffer.
|
||
|
ULONG * _pEndBuf;
|
||
|
ULONG _oBuffer; // offset when buffer is freed
|
||
|
CSmartBuffer _buffer;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CWBitStream
|
||
|
//
|
||
|
// Purpose: Writable Bit Stream
|
||
|
//
|
||
|
// Interface:
|
||
|
//
|
||
|
// History: 24-Aug-92 BartoszM Created
|
||
|
// 10-Apr-94 SrikantS Added the ability to open
|
||
|
// an existing stream for write
|
||
|
// access during Master Merge.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CWBitStream : public CBitStream
|
||
|
{
|
||
|
public:
|
||
|
CWBitStream ( CPhysStorage& phStorage ): CBitStream ( phStorage, TRUE ) {}
|
||
|
CWBitStream ( CPhysStorage& phStorage, const BitOffset & bitOff, BOOL fIncrSig = TRUE ) :
|
||
|
CBitStream( phStorage, bitOff, CSmartBuffer::eWriteExisting, fIncrSig ) {}
|
||
|
|
||
|
inline void PutBits(ULONG ul, unsigned cb);
|
||
|
|
||
|
void PutBytes(const BYTE * pb, unsigned cb);
|
||
|
|
||
|
void ZeroToEndOfPage();
|
||
|
|
||
|
void InitSignature();
|
||
|
|
||
|
#ifdef CIEXTMODE
|
||
|
void CiExtDump(void *ciExtSelf);
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
void NextDword();
|
||
|
|
||
|
void IPutBits(ULONG ul, unsigned cb);
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CPBitStream
|
||
|
//
|
||
|
// Purpose: Patch Bit Stream, used for back patching
|
||
|
//
|
||
|
// History: 24-Aug-92 BartoszM Created
|
||
|
//
|
||
|
// Notes: Seek is very cheap, since it doesn't load the page.
|
||
|
// Pages are loaded on demand when writing.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CPBitStream : public CBitStream
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CPBitStream ( CPhysStorage& phStorage );
|
||
|
|
||
|
void OverwriteBits(ULONG ul, unsigned cb);
|
||
|
|
||
|
__forceinline void SkipBits ( unsigned delta )
|
||
|
{
|
||
|
_bitOff += delta;
|
||
|
Win4Assert( _bitOff.Offset() < SMARTBUF_PAGE_SIZE_IN_BITS );
|
||
|
}
|
||
|
__forceinline void Seek ( const BitOffset& off )
|
||
|
{
|
||
|
_bitOff = off;
|
||
|
Win4Assert( _bitOff.Offset() < SMARTBUF_PAGE_SIZE_IN_BITS );
|
||
|
}
|
||
|
|
||
|
__forceinline void GetOffset ( BitOffset& off ) {
|
||
|
RtlCopyMemory( &off, &_bitOff, sizeof BitOffset );
|
||
|
}
|
||
|
|
||
|
|
||
|
#if CIDBG == 1
|
||
|
unsigned PeekBit();
|
||
|
virtual void Dump();
|
||
|
#endif // CIDBG == 1
|
||
|
|
||
|
#ifdef CIEXTMODE
|
||
|
void CiExtDump(void *ciExtSelf);
|
||
|
#endif
|
||
|
|
||
|
private:
|
||
|
|
||
|
void IOverwriteBits(ULONG ul, unsigned cb);
|
||
|
|
||
|
BitOffset _bitOff;
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Class: CRBitStream
|
||
|
//
|
||
|
// Purpose: Readable Bit Stream
|
||
|
//
|
||
|
// History: 24-Aug-92 BartoszM Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
class CRBitStream : public CBitStream
|
||
|
{
|
||
|
public:
|
||
|
CRBitStream ( CPhysStorage& phStorage ): CBitStream ( phStorage, FALSE ) {}
|
||
|
CRBitStream ( CPhysStorage& phStorage, const BitOffset& off )
|
||
|
: CBitStream ( phStorage, off, CSmartBuffer::eReadExisting ) {}
|
||
|
};
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBitStream::GetOffset, public
|
||
|
//
|
||
|
// Synopsis: Returns bit offset within the index.
|
||
|
//
|
||
|
// Arguments: [off] -- (out) bit offset
|
||
|
//
|
||
|
// History: 28-Aug-92 BartoszM Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline void CBitStream::GetOffset ( BitOffset& off )
|
||
|
{
|
||
|
off.Init( _buffer.PageNum(), Position() );
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBitStream::Position, private
|
||
|
//
|
||
|
// Synopsis: Returns bit position within current page
|
||
|
//
|
||
|
// History: 28-Aug-92 BartoszM Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline ULONG CBitStream::Position()
|
||
|
{
|
||
|
return CiPtrToUlong(_pCurPos - _buffer.Get() + 1) * ULONG_BITS - _cbitLeftDW;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBitStream::NextDword, private
|
||
|
//
|
||
|
// Synopsis: Increments current dword pointer,
|
||
|
// loads next page if necessary.
|
||
|
//
|
||
|
// History: 28-Aug-92 BartoszM Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline void CBitStream::NextDword()
|
||
|
{
|
||
|
_pCurPos++;
|
||
|
_cbitLeftDW = ULONG_BITS;
|
||
|
|
||
|
if (_pCurPos >= EndBuf())
|
||
|
{
|
||
|
LoadNextPage();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CWBitStream::NextDword, private
|
||
|
//
|
||
|
// Synopsis: Increments current dword pointer,
|
||
|
// loads new page if necessary.
|
||
|
//
|
||
|
// History: 28-Aug-92 BartoszM Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline void CWBitStream::NextDword()
|
||
|
{
|
||
|
_pCurPos++;
|
||
|
_cbitLeftDW = ULONG_BITS;
|
||
|
|
||
|
if (_pCurPos >= EndBuf())
|
||
|
{
|
||
|
LoadNewPage();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CWBitStream::PutBits, public
|
||
|
//
|
||
|
// Synopsis: Store bits in the buffer.
|
||
|
//
|
||
|
// Effects: Store the [cb] low bits in [ul] beginning at the 'bit-cursor'
|
||
|
//
|
||
|
// Arguments: [ul] -- A DWord containing data to store.
|
||
|
//
|
||
|
// [cb] -- The number of bits to store.
|
||
|
//
|
||
|
// History: 08-Jul-91 KyleP Created.
|
||
|
//
|
||
|
// Notes: Bits are stored 'big-endian'.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline void CWBitStream::PutBits(ULONG ul, unsigned cb)
|
||
|
{
|
||
|
// ciDebugOut (( DEB_BITSTM , "PutBits %d\n", cb ));
|
||
|
Win4Assert(cb != 0 && cb <= ULONG_BITS);
|
||
|
|
||
|
//
|
||
|
// The ULONG we're storing must be zero-filled at the top.
|
||
|
//
|
||
|
|
||
|
Win4Assert( (cb == ULONG_BITS) || ( (ul >> cb) == 0 ) );
|
||
|
|
||
|
//
|
||
|
// The easy case is the one where all the data fits in 1 dword.
|
||
|
//
|
||
|
|
||
|
if (cb <= _cbitLeftDW)
|
||
|
{
|
||
|
Win4Assert ( _pCurPos < EndBuf() );
|
||
|
_cbitLeftDW -= cb;
|
||
|
*_pCurPos |= (ul << _cbitLeftDW);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IPutBits(ul, cb);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBitStream::GetBits, public
|
||
|
//
|
||
|
// Synopsis: Retrieve bits from the buffer.
|
||
|
//
|
||
|
// Arguments: [cb] -- Count of bits to retrieve.
|
||
|
//
|
||
|
// History: 12-Jul-91 KyleP Created.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
__forceinline ULONG CBitStream::GetBits(unsigned cb)
|
||
|
{
|
||
|
// ciDebugOut (( DEB_BITSTM , "GetBits %d\n", cb ));
|
||
|
Win4Assert(cb != 0 && cb <= ULONG_BITS);
|
||
|
|
||
|
//
|
||
|
// The easy case is when the data can be extracted from the
|
||
|
// current dword.
|
||
|
//
|
||
|
|
||
|
if (cb <= _cbitLeftDW)
|
||
|
{
|
||
|
|
||
|
ULONG mask = 0xFFFFFFFF;
|
||
|
|
||
|
if (cb != ULONG_BITS)
|
||
|
{
|
||
|
mask = ~(mask << cb);
|
||
|
}
|
||
|
|
||
|
_cbitLeftDW -= cb;
|
||
|
return (*_pCurPos >> _cbitLeftDW) & mask;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return IGetBits( cb );
|
||
|
}
|
||
|
}
|
||
|
|