//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1991 - 2000.
//
//  File:       IRest.cxx
//
//  Contents:   Internal (non-public) restrictions.
//
//  Classes:    CInternalPropertyRestriction
//              COccRestriction
//              CWordRestriction
//              CSynRestriction
//              CRangeRestriction
//              CUnfilteredRestriction
//              CScopeRestriction
//              CPhraseRestriction
//
//  History:    19-Sep-91   BartoszM    Implemented.
//              29-Aug-92   MikeHew     Added serialization routines
//              30-Nov-92   KyleP       Removed CPhraseXpr
//              14-Jan-93   KyleP       Converted from expressions
//
//----------------------------------------------------------------------------

#include <pch.cxx>
#pragma hdrstop

#include <vkrep.hxx>
#include <norm.hxx>
#include <compare.hxx>

//+-------------------------------------------------------------------------
//
//  Function:   UnMarshallWideString
//
//  Synopsis:   Unmarshalls a wide string into a CoTaskMemAlloc'ed buffer.
//              This can't be in memdeser since it calls CoTaskMemAlloc,
//              which isn't available in ntdll.dll.
//
//  Arguments:  [stm]   -- stream from which string is deserialized
//
//  History:    22-Nov-95 dlee     Created from a few copies
//
//--------------------------------------------------------------------------

WCHAR * UnMarshallWideString( PDeSerStream & stm )
{
    ULONG cc = stm.GetULong();

    // Protect against attack.  We know our named pipes are < 64k

    if ( cc >= ( 65536 / sizeof WCHAR ) )
        return 0;

    XCoMem<WCHAR> xString( (WCHAR *) CoTaskMemAlloc( (cc + 1) * sizeof WCHAR ) );

    if ( xString.IsNull() )
    {
        // just eat the string

        WCHAR wc[10];

        while ( cc > 0 )
        {
            if ( cc >= 10 )
            {
                stm.GetWChar( wc, 10 );
                cc -= 10;
            }
            else
            {
                stm.GetWChar( wc, cc );
                cc = 0;
            }
        }
    }
    else
    {
        WCHAR * pwc = xString.GetPointer();
        stm.GetWChar( pwc, cc );
        pwc[cc] = 0;
    }

    return xString.Acquire();
} //UnMarshallWideString

WCHAR * UnMarshallWideStringNew( PDeSerStream & stm )
{
    ULONG cc = stm.GetULong();

    // Protect against attack.  We know our named pipes are < 64k

    if ( cc >= ( 65536 / sizeof WCHAR ) )
        THROW( CException( E_INVALIDARG ) );

    XArray<WCHAR> xString( cc + 1 );

    stm.GetWChar( xString.GetPointer(), cc );
    xString[cc] = 0;

    return xString.Acquire();
} //UnMarshallWideStringNew

//+-------------------------------------------------------------------------
//
//  Member:     CInternalPropertyRestriction::CInternalPropertyRestriction
//
//  Synopsis:   Creates property restriction
//
//  Arguments:  [relop] -- Relational operator (<, >, etc.)
//              [pid]   -- Property id
//              [prval] -- Property value
//              [pcrst] -- 'Helper' content restriction
//
//  History:    07-Mar-93 KyleP     Created
//
//--------------------------------------------------------------------------

CInternalPropertyRestriction::CInternalPropertyRestriction( ULONG relop,
                                                            PROPID pid,
                                                            CStorageVariant const & prval,
                                                            CRestriction * pcrst )
        : CRestriction( RTInternalProp, MAX_QUERY_RANK ),
          _relop( relop ),
          _pid( pid ),
          _prval( prval ),
          _pcrst( pcrst )
{
    if ( !_prval.IsValid() )
        THROW( CException( E_OUTOFMEMORY ) );
}


//+---------------------------------------------------------------------------
//
//  Member:     CInternalPropertyRestriction::CInternalPropertyRestriction
//
//  Synopsis:   Copy constructor
//
//  History:    30-May-95   SitaramR    Created.
//
//----------------------------------------------------------------------------

CInternalPropertyRestriction::CInternalPropertyRestriction(
    CInternalPropertyRestriction const & intPropRst )
    : CRestriction( RTInternalProp, intPropRst.Weight() ),
      _relop( intPropRst.Relation() ),
      _pid( intPropRst.Pid() ),
      _prval( intPropRst.Value() ),
      _pcrst( 0 )
{
    if ( !_prval.IsValid() )
        THROW( CException( E_OUTOFMEMORY ) );

    CRestriction *pHelperRst = intPropRst.GetContentHelper();

    if ( pHelperRst )
        _pcrst  = pHelperRst->Clone();
}




//+-------------------------------------------------------------------------
//
//  Member:     CInternalPropertyRestriction::~CInternalPropertyRestriction
//
//  Synopsis:   Cleanup restriction
//
//  History:    01-Feb-93 KyleP     Created
//
//--------------------------------------------------------------------------

CInternalPropertyRestriction::~CInternalPropertyRestriction()
{
    delete _pcrst;

    SetType( RTNone );                  // Avoid recursion.
}

void CInternalPropertyRestriction::Marshall( PSerStream & stm ) const
{
    stm.PutULong( _relop );
    stm.PutULong( _pid );
    _prval.Marshall( stm );

    if ( 0 == _pcrst )
        stm.PutByte( 0 );
    else
    {
        stm.PutByte( 1 );
        _pcrst->Marshall( stm );
    }
}

CInternalPropertyRestriction::CInternalPropertyRestriction( ULONG ulWeight,
                                                            PDeSerStream & stm )
        : CRestriction( RTInternalProp, ulWeight ),
          _relop( stm.GetULong() ),
          _pid( stm.GetULong() ),
          _prval( stm )
{
    if ( !_prval.IsValid() )
        THROW( CException( E_OUTOFMEMORY ) );

    BYTE fRst = stm.GetByte();

    if ( fRst )
        _pcrst = CRestriction::UnMarshall( stm );
    else
        _pcrst = 0;
}


//+---------------------------------------------------------------------------
//
//  Member:     CInternalPropertyRestriction::Clone, public
//
//  Synopsis:   Clones an internal property restriction
//
//  History:    30-May-95   SitaramR    Created.
//
//----------------------------------------------------------------------------

CInternalPropertyRestriction *CInternalPropertyRestriction::Clone() const
{
    return new CInternalPropertyRestriction( *this );
}

//+---------------------------------------------------------------------------
//
//  Member:     COccRestriction::COccRestriction, public
//
//  Synopsis:   Creates occurrence restriction
//
//  Arguments:  [ulType]  -- type of restriction
//              [ulWeight] -- weight
//              [occ] -- occurrence
//              [cPrevNoiseWords] -- count of previous noise words skipped
//              [cPostNoiseWords] -- count of post noise words skipped
//
//  History:    29-Nov-94   SitaramR    Created.
//
//----------------------------------------------------------------------------

COccRestriction::COccRestriction( ULONG ulType, ULONG ulWeight, OCCURRENCE occ,
                                  ULONG cPrevNoiseWords, ULONG cPostNoiseWords )
            : CRestriction( ulType, ulWeight ),
              _occ( occ ),
              _cPrevNoiseWords( cPrevNoiseWords),
              _cPostNoiseWords( cPostNoiseWords )
{
}


//+-------------------------------------------------------------------------
//
//  Member:     COccRestriction::~COccRestriction, public
//
//  Synopsis:   Cleanup occurrence restriction
//
//  Notes:      This destructor simulates virtual destruction.
//
//              Classes derived from COccRestriction must be sure to set their
//              restriction type to RTNone in their destructor, so when the
//              base destructor below is called the derived destructor is
//              not called a second time.
//
//  History:    29-Nov-94    SitaramR     Created
//
//--------------------------------------------------------------------------

COccRestriction::~COccRestriction()
{
    switch ( Type() )
    {
    case RTNone:
        break;

    case RTWord:
        ((CWordRestriction *)this)->CWordRestriction::~CWordRestriction();
        break;

    case RTSynonym:
        ((CSynRestriction *)this)->CSynRestriction::~CSynRestriction();
        break;

    default:
        ciDebugOut(( DEB_ERROR, "Unhandled child (%d) of class COccRestriction\n",
                     Type() ));
        Win4Assert( !"Unhandled child of class COccRestriction" );
        break;
    }
}

//+-------------------------------------------------------------------------
//
//  Member:     COccRestriction::IsValid(), public
//
//  History:    14-Nov-95 KyleP     Created
//
//  Returns:    TRUE if all memory allocations, etc. succeeded.
//
//--------------------------------------------------------------------------

BOOL COccRestriction::IsValid() const
{
    BOOL fValid = TRUE;

    switch ( Type() )
    {
    case RTWord:
        fValid = ((CWordRestriction *)this)->CWordRestriction::IsValid();
        break;

    case RTSynonym:
        fValid = ((CSynRestriction *)this)->CSynRestriction::IsValid();
        break;

    default:
        ciDebugOut(( DEB_ERROR, "Unhandled child (%d) of class COccRestriction\n",
                     Type() ));
        Win4Assert( !"Unhandled child of class COccRestriction" );
        fValid = FALSE;
        break;
    }

    return fValid;
}


//+-------------------------------------------------------------------------
//
//  Member:     COccRestriction::Marshall, public
//
//  Synopsis:   Serialize occurrence restriction
//
//  Arguments:  [stm] -- stream to serialize to
//
//  History:    29-Nov-94    SitaramR     Created
//
//--------------------------------------------------------------------------

void COccRestriction::Marshall( PSerStream& stm ) const
{
    stm.PutULong( _occ );
    stm.PutULong( _cPrevNoiseWords );
    stm.PutULong( _cPostNoiseWords );
    switch ( Type() )
    {
    case RTWord:
        ((CWordRestriction *)this)->Marshall( stm );
        break;

    case RTSynonym:
        ((CSynRestriction *)this)->Marshall( stm );
        break;

    default:
        ciDebugOut(( DEB_ERROR, "Unhandled child (%d) of class COccRestriction\n",
                     Type() ));
        Win4Assert( !"Unhandled child of class COccRestriction" );
        break;

    }
}


//+-------------------------------------------------------------------------
//
//  Member:     COccRestriction::COccRestriction, public
//
//  Synopsis:   De-serialize occurrence restriction
//
//  Arguments:  [ulType] -- type of occurrence restriction
//              [ulWeight] -- weight of occurrence restriction
//              [stm] -- stream to serialize from
//
//  History:    29-Nov-94    SitaramR     Created
//
//--------------------------------------------------------------------------

COccRestriction::COccRestriction( ULONG ulType, ULONG ulWeight, PDeSerStream& stm )
        : CRestriction( ulType, ulWeight )
{
    _occ = stm.GetULong();
    _cPrevNoiseWords = stm.GetULong();
    _cPostNoiseWords = stm.GetULong();
}




//+-------------------------------------------------------------------------
//
//  Member:     COccRestriction::Clone, public
//
//  Synopsis:   Clone occurrence restriction
//
//  History:    29-Nov-94    SitaramR     Created
//
//--------------------------------------------------------------------------

COccRestriction *COccRestriction::Clone() const
{
    switch ( Type() )
    {
    case RTWord:
        return ((CWordRestriction *)this)->Clone();
        break;

    case RTSynonym:
        return ((CSynRestriction *)this)->Clone();
        break;

    default:
        ciDebugOut(( DEB_ERROR, "Unhandled child (%d) of class COccRestriction\n",
                     Type() ));
        Win4Assert( !"Unhandled child of class COccRestriction" );
        return 0;
        break;
    }
}



//+---------------------------------------------------------------------------
//
//  Member:     CWordRestriction::CWordRestriction, public
//
//  Synopsis:   Creates word expression
//
//  Arguments:  [keyBuf]  -- key to be matched
//              [occ]     -- occurrence (if in phrase)
//              [isRange] -- TRUE if key is a prefix
//
//  History:    19-Sep-91   BartoszM    Created.
//
//----------------------------------------------------------------------------

CWordRestriction::CWordRestriction ( const CKeyBuf& keyBuf,
                                     OCCURRENCE occ,
                                     ULONG cPrevNoiseWords,
                                     ULONG cPostNoiseWords,
                                     BOOL isRange )
        : COccRestriction( RTWord, MAX_QUERY_RANK, occ, cPrevNoiseWords, cPostNoiseWords ),
          _isRange(isRange)
{
    // copy after init to 0 in case new fails and ~CWordRestriction is
    // called from ~CRestriction

    _key = keyBuf;
}



//+---------------------------------------------------------------------------
//
//  Member:     CWordRestriction::CWordRestriction, public
//
//  Synopsis:   Copy constuctor
//
//  Arguments:  [wordRst]  -- word restriction to be copied
//
//  History:    29-Nov-94   SitaramR    Created.
//
//----------------------------------------------------------------------------

CWordRestriction::CWordRestriction( const CWordRestriction& wordRst )
    : COccRestriction( RTWord, wordRst.Weight(), wordRst.Occurrence(),
                       wordRst.CountPrevNoiseWords(), wordRst.CountPostNoiseWords() ),
      _isRange( wordRst.IsRange() )
{
    // copy after init to 0 in case new fails and ~CWordRestriction is
    // called from ~CRestriction

    _key = *wordRst.GetKey();
}




//+-------------------------------------------------------------------------
//
//  Member:     CWordRestriction::~CWordRestriction, public
//
//  Synopsis:   Cleanup restriction
//
//  History:    01-Feb-93 KyleP     Created
//
//--------------------------------------------------------------------------

CWordRestriction::~CWordRestriction()
{
    SetType( RTNone );                  // Avoid recursion.
}

void CWordRestriction::Marshall( PSerStream & stm ) const
{
    _key.Marshall( stm );
    stm.PutByte( (BYTE)_isRange );
}

CWordRestriction::CWordRestriction( ULONG ulWeight, PDeSerStream & stm )
        : COccRestriction( RTWord, ulWeight, stm ),
          _key( stm ),
          _isRange( stm.GetByte() )
{
}


//+---------------------------------------------------------------------------
//
//  Member:     CWordRestriction::Clone, public
//
//  Synopsis:   Clone restriction
//
//  History:    29-Nov-94   SitaramR   Created.
//
//----------------------------------------------------------------------------

CWordRestriction *CWordRestriction::Clone()  const
{
    return new CWordRestriction( *this );
}



//+---------------------------------------------------------------------------
//
//  Member:     CSynRestriction::CSynRestriction, public
//
//  Synopsis:   Creates Syn expression
//
//  Arguments:  [occ] -- occurrence (if in phrase)
//              [isRange] -- is it range?
//
//  History:    07-Feb-92   BartoszM    Created.
//
//----------------------------------------------------------------------------

const int cSynonyms = 2; // default initial count of synonyms

CSynRestriction::CSynRestriction ( const CKey& key,
                                   OCCURRENCE occ,
                                   ULONG cPrevNoiseWords,
                                   ULONG cPostNoiseWords,
                                   BOOL isRange )
        : COccRestriction( RTNone, MAX_QUERY_RANK, occ, cPrevNoiseWords, cPostNoiseWords ),
          _keyArray( cSynonyms, TRUE ),
          _isRange(isRange)
{
    _keyArray.Add ( key );
    SetType( RTSynonym );
}




//+---------------------------------------------------------------------------
//
//  Member:     CSynRestriction::CSynRestriction, public
//
//  Synopsis:   Copy constuctor
//
//  Arguments:  [synRst]  -- synonym restriction to be copied
//
//  History:    29-Nov-94   SitaramR    Created.
//
//----------------------------------------------------------------------------

CSynRestriction::CSynRestriction( CSynRestriction& synRst )
    : COccRestriction( RTNone, synRst.Weight(), synRst.Occurrence(),
                       synRst.CountPrevNoiseWords(), synRst.CountPostNoiseWords() ),
      _keyArray( synRst.GetKeys(), TRUE ),
      _isRange( synRst.IsRange() )
{
    SetType( RTSynonym );
}



//+-------------------------------------------------------------------------
//
//  Member:     CSynRestriction::~CSynRestriction, public
//
//  Synopsis:   Cleanup restriction
//
//  History:    01-Feb-93 KyleP     Created
//
//--------------------------------------------------------------------------

CSynRestriction::~CSynRestriction()
{
    SetType( RTNone );                  // Avoid recursion.
}

void CSynRestriction::Marshall( PSerStream & stm ) const
{
    _keyArray.Marshall( stm );
    stm.PutByte( (BYTE)_isRange );
}

CSynRestriction::CSynRestriction( ULONG ulWeight, PDeSerStream & stm )
        : COccRestriction( RTNone, ulWeight, stm),
          _keyArray( stm, TRUE ),
          _isRange( stm.GetByte() )
{
    SetType( RTSynonym );
}



//+---------------------------------------------------------------------------
//
//  Member:     CSynRestriction::Clone, public
//
//  Synopsis:   Clone restriction
//
//  History:    29-Nov-94   SitaramR   Created.
//
//----------------------------------------------------------------------------

CSynRestriction *CSynRestriction::Clone() const
{
    return new CSynRestriction( *(CSynRestriction *)this );
}




//+---------------------------------------------------------------------------
//
//  Member:     CSynRestriction::AddKey, public
//
//  Synopsis:   Adds synonym key
//
//  Arguments:  [keyBuf] -- key
//
//  History:    07-Feb-92   BartoszM    Created.
//
//----------------------------------------------------------------------------

void CSynRestriction::AddKey ( const CKeyBuf& Key )
{
    _keyArray.Add ( Key );
}

//+---------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::CRangeRestriction, public
//
//  Synopsis:   Creates word expression
//
//  Arguments:  [pid] -- property id
//              [keyStart] -- starting key
//              [keyEnd] -- ending key
//
//  History:    24-Sep-92   BartoszM    Created.
//
//----------------------------------------------------------------------------

CRangeRestriction::CRangeRestriction()
        : CRestriction( RTRange, MAX_QUERY_RANK )
{
}


//+---------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::CRangeRestriction
//
//  Synopsis:   Copy constructor
//
//  History:    30-May-95   SitaramR    Created
//
//----------------------------------------------------------------------------

CRangeRestriction::CRangeRestriction( const CRangeRestriction& rangeRst )
    : CRestriction( RTNone, rangeRst.Weight() )
{
    const CKey *pKeyStart = rangeRst.GetStartKey();

    if ( pKeyStart )
        _keyStart = *pKeyStart;

    const CKey *pKeyEnd = rangeRst.GetEndKey();

    if ( pKeyEnd )
        _keyEnd = *pKeyEnd;

    SetType( RTRange );
}


//+-------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::~CRangeRestriction, public
//
//  Synopsis:   Cleanup restriction
//
//  History:    01-Feb-93 KyleP     Created
//
//--------------------------------------------------------------------------

CRangeRestriction::~CRangeRestriction()
{
    SetType( RTNone );                  // Avoid recursion.
}

void CRangeRestriction::Marshall( PSerStream & stm ) const
{
    _keyStart.Marshall( stm );
    _keyEnd.Marshall( stm );
}

CRangeRestriction::CRangeRestriction( ULONG ulWeight, PDeSerStream & stm )
        : CRestriction( RTNone, ulWeight ),
          _keyStart( stm ),
          _keyEnd( stm )
{
    SetType( RTRange );
}

//+---------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::SetStartKey, public
//
//  Arguments:  [keyStart] -- starting key
//
//  History:    24-Sep-92   BartoszM    Created.
//
//----------------------------------------------------------------------------

void CRangeRestriction::SetStartKey ( const CKeyBuf& keyStart )
{
    _keyStart = keyStart;
}

//+---------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::SetEndKey, public
//
//  Arguments:  [keyEnd] -- Ending key
//
//  History:    24-Sep-92   BartoszM    Created.
//
//----------------------------------------------------------------------------

void CRangeRestriction::SetEndKey ( const CKeyBuf& keyEnd )
{
    _keyEnd = keyEnd;
}



//+---------------------------------------------------------------------------
//
//  Member:     CRangeRestriction::Clone
//
//  Synopsis:   Clones a range restriction
//
//  History:    30-May-95   SitaramR    Created
//
//----------------------------------------------------------------------------

CRangeRestriction *CRangeRestriction::Clone() const
{
    return new CRangeRestriction( *this );
}




//+---------------------------------------------------------------------------
//
//  Member:     CUnfilteredRestriction::CUnfilteredRestriction, public
//
//  History:    10-Nov-94   KyleP       Created.
//
//  Notes:      This restriction is just a very special case of range
//              restriction that searches only for a particular value.
//              Standard procedure to create a range restriction is
//              sidetracked to save code.
//
//----------------------------------------------------------------------------

CUnfilteredRestriction::CUnfilteredRestriction()
{
    static const BYTE abUnfiltered[] = { VT_UI1,
                                  (BYTE)(pidUnfiltered >> 24),
                                  (BYTE)(pidUnfiltered >> 16),
                                  (BYTE)(pidUnfiltered >> 8),
                                  (BYTE) pidUnfiltered,
                                  0,
                                  1 };

    static CKeyBuf keyUnfilteredRange( pidUnfiltered, abUnfiltered, sizeof(abUnfiltered) );

    SetStartKey( keyUnfilteredRange );
    SetEndKey( keyUnfilteredRange );

#if DBG == 1 && CIDBG == 1
    CRangeKeyRepository krep;
    CValueNormalizer norm( krep );
    OCCURRENCE occ = 1;
    CStorageVariant var;
    var.SetBOOL( (VARIANT_BOOL)0xFFFF );

    norm.PutValue( pidUnfiltered, occ, var );
    norm.PutValue( pidUnfiltered, occ, var );

    CRestriction * prst = krep.AcqRst();

    Win4Assert( prst->Type() == RTRange );

    CRangeRestriction * pRange = (CRangeRestriction *)prst;

    Win4Assert( pRange->GetStartKey()->Compare( *GetStartKey() ) == 0 );
    Win4Assert( pRange->GetEndKey()->Compare( *GetEndKey() ) == 0 );

    delete prst;
#endif
}



//+---------------------------------------------------------------------------
//
//  Member:     CPhraseRestriction::CPhraseRestriction, public
//
//  Synopsis:   Deserializes phrase restriction
//
//  Arguments:  [ulWeight]  -- restriction weight
//              [stm] -- stream to deserialize from
//
//  History:    29-Nov-94   SitaramR    Created.
//
//----------------------------------------------------------------------------

CPhraseRestriction::CPhraseRestriction( ULONG ulWeight, PDeSerStream& stm )
        : CNodeRestriction( RTPhrase, ulWeight, stm  )
{
#if CIDBG == 1
    for ( unsigned i = 0; i < _cNode; i++ )
        Win4Assert( _paNode[i]->Type() == RTWord || _paNode[i]->Type() == RTSynonym );
#endif
}

//+---------------------------------------------------------------------------
//
//  Member:     CPhraseRestriction::~CPhraseRestriction, public
//
//  History:    29-Nov-94   SitaramR    Created.
//
//----------------------------------------------------------------------------

CPhraseRestriction::~CPhraseRestriction()
{
    if ( 0 != _paNode )
    {
        for ( unsigned i = 0; i < _cNode; i++ )
        {
            #if CIDBG == 1
                if ( 0 != _paNode[i] )
                {
                    Win4Assert( _paNode[i]->Type() == RTWord ||
                                _paNode[i]->Type() == RTSynonym );
                }
            #endif // CIDBG

            delete (COccRestriction *) _paNode[i];
        }

        delete [] _paNode;
    }

    SetType( RTNone );                  // Avoid recursion.
}


CScopeRestriction::CScopeRestriction( WCHAR const * pwcsPath, BOOL fRecursive, BOOL fVirtual )
        : CRestriction( RTScope, MAX_QUERY_RANK ),
          _fValid( FALSE ),
          _fRecursive( fRecursive ),
          _fVirtual( fVirtual )
{
    SetPath( pwcsPath );
}

CScopeRestriction * CScopeRestriction::Clone() const
{
    return( new CScopeRestriction( _lowerFunnyPath.GetActualPath(), _fRecursive, _fVirtual ) );
}

CScopeRestriction::~CScopeRestriction()
{
    SetType( RTNone );                  // Avoid recursion.
}

void CScopeRestriction::Marshall( PSerStream & stm ) const
{
    stm.PutWString( _lowerFunnyPath.GetActualPath() );
    stm.PutULong( _lowerFunnyPath.GetActualLength() );
    stm.PutULong( _fRecursive );
    stm.PutULong( _fVirtual );
}

CScopeRestriction::CScopeRestriction( ULONG ulWeight, PDeSerStream & stm )
        : CRestriction( RTScope, ulWeight ),
          _fValid( FALSE )
{
    XCoMem<WCHAR> xString( UnMarshallWideString( stm ) );

    //
    // Simple validity checks; not all-inclusive.  Just
    // return with _fValid set to FALSE and the query
    // will fail with an out of memory error.
    //

    // We don't support long paths for scopes.

    if ( wcslen( xString.GetPointer() ) >= MAX_PATH )
        return;

    // We don't support the NTFS special stream syntax

    if ( 0 != wcsstr( xString.GetPointer(), L"::$" ) )
        return;

    stm.GetULong(); // length not needed

    _fRecursive = stm.GetULong();
    _fVirtual = stm.GetULong();
    _lowerFunnyPath.SetPath( xString.Acquire() );
    _fValid = TRUE; // since we have a valid path
}

CScopeRestriction & CScopeRestriction::operator =(
    CScopeRestriction const & source )
{
    _lowerFunnyPath = source._lowerFunnyPath;
    _fRecursive = source._fRecursive;
    _fVirtual = source._fVirtual;
    _fValid = source._fValid;

    return *this;
}

//+---------------------------------------------------------------------------
//
//  Method:     CScopeRestriction::SetPath
//
//  Synopsis:   Validates and sets a path in a scope restriction
//
//  History:    24-Oct-96   dlee    Created.
//
//----------------------------------------------------------------------------

void CScopeRestriction::SetPath( WCHAR const * pwcsPath )
{
    _fValid = FALSE;

    //
    // Simple validity checks; not all-inclusive.  Just
    // return with _fValid set to FALSE and the query
    // wil fail with an out of memory error.
    //

    // We don't support long paths for scopes.

    if ( wcslen( pwcsPath ) >= MAX_PATH )
        return;

    // We don't support the NTFS special stream syntax

    if ( 0 != wcsstr( pwcsPath, L"::$" ) )
        return;

    _lowerFunnyPath.Truncate(0);
    if ( pwcsPath)
    {
        _lowerFunnyPath.SetPath( pwcsPath );
        _fValid = TRUE;
    }
} //SetPath

//+---------------------------------------------------------------------------
//
//  Function:   ValidateScopeRestriction
//
//  Synopsis:   Verifies a scope restriction looks ok.  Can't use
//              CRestriction::IsValid since this needs to make sure there
//              aren't any odd nodes in the tree (like proximity, etc.)
//
//  Returns:    TRUE if it is ok, FALSE otherwise
//
//  History:    24-Oct-96   dlee    Created.
//
//----------------------------------------------------------------------------

BOOL ValidateScopeRestriction( CRestriction * pRst )
{
    if ( 0 == pRst )
        return FALSE;

    switch ( pRst->Type() )
    {
#if 0 // someday we might support exclusion scopes
        case RTNot:
        {
            CRestriction *p = ((CNotRestriction *)pRst)->GetChild();
            return ValidateScopeRestriction( p );
            break;
        }
        case RTAnd:
#endif // 0 // exclusion scopes
        case RTOr:
        {
            CNodeRestriction * p = pRst->CastToNode();
            for ( ULONG x = 0; x < p->Count(); x++ )
            {
                if ( !ValidateScopeRestriction( p->GetChild( x ) ) )
                    return FALSE;
            }
            break;
        }
        case RTScope:
        {
            CScopeRestriction *p = (CScopeRestriction *) pRst;
            if ( !p->IsValid() )
                return FALSE;
            break;
        }
        default :
        {
            return FALSE;
        }
    }

    return TRUE;
} //ValidateScopeRestriction

#if CIDBG == 1

//+-------------------------------------------------------------------------
//
//  Function:   DisplayChar
//
//  Synopsis:   Debug print the non-ascii text buffer
//
//  Arguments:  [pwString] -- Pointer to string (not null terminated)
//              [cString]  -- len of the string in char
//              [infolevel] --
//
//  History:    22-Apr-98   KitmanH      Created
//
//--------------------------------------------------------------------------

void DisplayChar( WCHAR * pwString, DWORD cString, ULONG infolevel )
{

    BOOL fOk = TRUE;
    for ( unsigned i = 0; i < cString; i++ )
    {
        if ( pwString[i] > 0xFF )
        {
            fOk = FALSE;
            break;
        }
    }

    if ( fOk )
    {
        unsigned j = 0;
        WCHAR awcTemp[71];

        for ( unsigned i = 0; i < cString; i++ )
        {
            awcTemp[j] = pwString[i];
            j++;

            if ( j == sizeof(awcTemp)/sizeof(awcTemp[0]) - 1 )
            {
                awcTemp[j] = 0;
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\"%ws\"", awcTemp ));
                j = 0;
            }
        }

        awcTemp[j] = 0;
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\"%ws\"", awcTemp ));
    }
    else
    {
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "0x" ));

        unsigned j = 0;

        for ( unsigned i = 0; i < cString; i++ )
        {
            if ( 0 == j )
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "%04X", pwString[i] ));
            else if ( 14 == j )
            {
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, " %04X\n", pwString[i] ));
            }
            else
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, " %04X", pwString[i] ));

            j++;

            if ( j > 14 )
                j = 0;
        }

    }

}

void Display( CRestriction * pRst, int indent, ULONG infolevel )
{
    vqDebugOut(( infolevel, "    " ));

    for ( int i = 0; i < indent; i++ )
    {
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "    " ));
    }

    switch ( pRst->Type() )
    {
    case RTContent:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME,
                     "CONTENT: \"%ws\", LOCALE: %lu\n",
                     ((CContentRestriction *)pRst)->GetPhrase(),
                     ((CContentRestriction *)pRst)->GetLocale() ));
        break;

    case RTNatLanguage:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME,
                     "NATURAL LANGUAGE: \"%ws\", LOCALE: %lu\n",
                     ((CNatLanguageRestriction *)pRst)->GetPhrase(),
                     ((CNatLanguageRestriction *)pRst)->GetLocale() ));
        break;

    case RTWord:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "WORD%s: ",
                     ((CWordRestriction *)pRst)->IsRange() ? " PREFIX" : "" ));
        DisplayChar( ((CWordRestriction *)pRst)->GetKey()->GetStr(),
                     ((CWordRestriction *)pRst)->GetKey()->StrLen(),
                     infolevel
                   );

        vqDebugOut(( infolevel | DEB_NOCOMPNAME,
                     " PID %d OCC %d, WEIGHT %d\n",
                     ((CWordRestriction *)pRst)->Pid(),
                     ((CWordRestriction *)pRst)->Occurrence(),
                     ((CWordRestriction *)pRst)->Weight() ));
        break;

    case RTSynonym:
    {
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "SYNONYM: OCC %d ",
                     ((CSynRestriction *)pRst)->Occurrence() ));
        CKeyArray & keys = ((CSynRestriction *)pRst)->GetKeys();

        for ( int i = 0; i < keys.Count(); i++ )
        {
            DisplayChar( keys.Get(i).GetStr(), keys.Get(i).StrLen(),
                         infolevel );
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, " " ));
        }
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\n" ));
        break;
    }

    case RTRange:
    {
        CRangeRestriction * pr = (CRangeRestriction *)pRst;

        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "RANGE: " ));

        char * pc = new char[pr->GetStartKey()->Count() * 2 +
                                            1 +
                                            pr->GetEndKey()->Count() * 2 +
                                            2];

        for ( unsigned i = 0; i < pr->GetStartKey()->Count(); i++ )
            sprintf( pc + i*2, "%02x", pr->GetStartKey()->GetBuf()[i] );

        pc[i*2] = '-';

        for ( unsigned j = 0; j < pr->GetEndKey()->Count(); j++ )
            sprintf( pc + i*2 + 1 + j*2, "%02x", pr->GetEndKey()->GetBuf()[j] );

        pc[i*2 + 1 + j*2] = '\n';
        pc[i*2 + 1 + j*2 + 1] = 0;
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, pc ));
        delete [] pc;
        break;
    }

    case RTProperty:
        if ( ((CPropertyRestriction *)pRst)->Relation() == PRRE )
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "REGEX " ));
        else
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "PROPERTY " ));

        ((CPropertyRestriction *) pRst)->Value().DisplayVariant(
                                                    infolevel | DEB_NOCOMPNAME,
                                                    0);
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\n" ));
        break;

    case RTInternalProp:
    {
        CInternalPropertyRestriction * pir = (CInternalPropertyRestriction *)pRst;

        if ( pir->Relation() == PRRE )
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "REGEX pid(0x%lx) ",
                         pir->Pid() ));
        else
        {
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "PROPERTY pid(0x%lx) ", pir->Pid() ));
            switch ( getBaseRelop( pir->Relation() ) )
            {
            case PRLT:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "< " ));
                break;

            case PRLE:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "<= " ));
                break;

            case PRGT:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "> " ));
                break;

            case PRGE:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, ">= " ));
                break;

            case PREQ:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "== " ));
                break;

            case PRNE:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "!= " ));
                break;

            case PRAllBits:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "All bits " ));
                break;

            case PRSomeBits:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "Some bits " ));
                break;

            default:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "??? " ));
                break;
            }

            if ( pir->Relation() & PRAll )
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "All " ));
            else if ( pir->Relation() & PRAny )
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "Any " ));

        }

        pir->Value().DisplayVariant(infolevel | DEB_NOCOMPNAME, 0);

        if ( pir->GetContentHelper() )
        {
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\n" ));

            for ( int i = 0; i < indent+5; i++ )
            {
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "    " ));
            }
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "HELPER:\n" ));
            Display( pir->GetContentHelper(), indent+3, infolevel );
        }
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "\n" ));
        break;
    }

    case RTNot:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "NOT\n" ));
        Display( ((CNotRestriction *)pRst)->GetChild(), indent + 1, infolevel );
        break;

    case RTAnd:
    case RTOr:
    case RTProximity:
    case RTVector:
    case RTPhrase:
    {
        switch( pRst->Type() )
        {
        case RTAnd:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "AND\n" ));
            break;

        case RTOr:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "OR\n" ));
            break;

        case RTNot:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "NOT\n" ));
            break;

        case RTProximity:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "PROXIMITY\n" ));
            break;

        case RTVector:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "VECTOR " ));
            switch ( ((CVectorRestriction *)pRst)->RankMethod() )
            {
            case VECTOR_RANK_MIN:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(Min)\n" ));
                break;

            case VECTOR_RANK_MAX:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(Max)\n" ));
                break;

            case VECTOR_RANK_INNER:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(Inner Product)\n" ));
                break;

            case VECTOR_RANK_DICE:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(Dice Coefficient)\n" ));
                break;

            case VECTOR_RANK_JACCARD:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(Jaccard Coefficient)\n" ));
                break;

            default:
                vqDebugOut(( infolevel | DEB_NOCOMPNAME, "(???)\n" ));
                break;
            }
            break;

        case RTPhrase:
            vqDebugOut(( infolevel | DEB_NOCOMPNAME, "PHRASE\n" ));
            break;
        }

        CNodeRestriction * pNodeRst = pRst->CastToNode();

        for ( UINT i = 0; i < pNodeRst->Count(); i++ )
        {
            Display( pNodeRst->GetChild( i ), indent + 1, infolevel );
        }
        break;
    }

    case RTNone:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "NONE -- empty\n" ));
        break;

    default:
        vqDebugOut(( infolevel | DEB_NOCOMPNAME, "UNKNOWN\n" ));
        break;

    }
}

#endif // CIDBG == 1