windows-nt/Source/XPSP1/NT/inetsrv/query/cindex/bitstm.hxx

470 lines
12 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// 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 );
}
}