//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) 1992, Microsoft Corporation.
//
//  File:       expst.cxx
//
//  Contents:   CExposedStream code
//
//--------------------------------------------------------------------------

#include <exphead.cxx>

#include <pbstream.hxx>
#include <expst.hxx>
#include <lock.hxx>
#include <seekptr.hxx>
#include <logfile.hxx>

// Maximum stream size supported by exposed streams
// This is MAX_ULONG with one subtracted so that
// the seek pointer has a spot to sit even at the
// end of the stream
#define CBMAXSTREAM 0xfffffffeUL
// Maximum seek pointer value
#define CBMAXSEEK (CBMAXSTREAM+1)

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::CExposedStream, public
//
//  Synopsis:   Empty object constructor
//
//---------------------------------------------------------------


CExposedStream::CExposedStream(void)
{
    olDebugOut((DEB_ITRACE, "In  CExposedStream::CExposedStream()\n"));
    _cReferences = 0;
    _ulAccessLockBase = 0;
    _psp = NULL;
    _pst = NULL;
    olDebugOut((DEB_ITRACE, "Out CExposedStream::CExposedStream\n"));
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::InitWithSeekPtr, public
//
//  Synopsis:   Base constructor
//
//  Arguments:  [pst] - Public stream
//              [pdfb] - DocFile basis
//              [ppc] - Context
//              [fOwnContext] - Whether this object owns the context
//              [psp] - Seek pointer or NULL for new seek pointer
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

SCODE CExposedStream::Init(CPubStream *pst,
                           CSeekPointer *psp)
{
    SCODE sc;

    olDebugOut((DEB_ITRACE, "In  CExposedStream::Init("
                "%p, %p)\n", pst, psp));    
    if (psp == NULL)
        olMem(_psp = new CSeekPointer(0));
    else
        _psp = psp;
    _pst = pst;
    _cReferences = 1;
    _sig = CEXPOSEDSTREAM_SIG;
    olDebugOut((DEB_ITRACE, "Out CExposedStream::InitWithSeekPtr\n"));
    return S_OK;

EH_Err:
    return sc;
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::~CExposedStream, public
//
//  Synopsis:   Destructor
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------


inline
CExposedStream::~CExposedStream(void)
{
    olDebugOut((DEB_ITRACE, "In  CExposedStream::~CExposedStream\n"));
    olAssert(_cReferences == 0);
    _sig = CEXPOSEDSTREAM_SIGDEL;
    if (_pst)
        _pst->CPubStream::vRelease();
    if (_psp)
        _psp->CSeekPointer::vRelease();
    olDebugOut((DEB_ITRACE, "Out CExposedStream::~CExposedStream\n"));
}


//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Read, public
//
//  Synopsis:   Read from a stream
//
//  Arguments:  [pb] - Buffer
//              [cb] - Count of bytes to read
//              [pcbRead] - Return number of bytes read
//
//  Returns:    Appropriate status code
//
//  Modifies:   [pcbRead]
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Read(VOID HUGEP *pb, ULONG cb, ULONG *pcbRead)
{
    SCODE sc;
    ULONG cbRead = 0;

    olLog(("%p::In  CExposedStream::Read(%p, %lu, %p)\n",
           this, pb, cb, pcbRead));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Read(%p, %lu, %p)\n",
                 pb, cb, pcbRead));
    TRY
    {
        if (pcbRead)
        {
            olChkTo(EH_BadPtr, ValidateOutBuffer(pcbRead, sizeof(ULONG)));
        }

        olChk(ValidateHugeOutBuffer(pb, cb));
        olChk(Validate());
        sc = _pst->ReadAt(_psp->GetPos(), pb, cb,
                          (ULONG STACKBASED *)&cbRead);
        olAssert(CBMAXSEEK-_psp->GetPos() >= cbRead);
        _psp->SetPos(_psp->GetPos()+cbRead);
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Read => %lu\n", cbRead));

EH_Err:
    if (pcbRead)
    {
        *pcbRead = cbRead;
        olLog(("%p::Out CExposedStream::Read().  *pcbRead == %lu, ret = %lx\n",
               this, *pcbRead, sc));
    }
    else
    {
        olLog(("%p::Out CExposedStream::Read().  ret == %lx\n", this, sc));
    }

EH_BadPtr:
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Write, public
//
//  Synopsis:   Write to a stream
//
//  Arguments:  [pb] - Buffer
//              [cb] - Count of bytes to write
//              [pcbWritten] - Return of bytes written
//
//  Returns:    Appropriate status code
//
//  Modifies:   [pcbWritten]
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Write(
        VOID const HUGEP *pb,
        ULONG cb,
        ULONG *pcbWritten)
{
    SCODE sc;
    ULONG cbWritten = 0;

    olLog(("%p::In  CExposedStream::Write(%p, %lu, %p)\n",
           this, pb, cb, pcbWritten));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Write(%p, %lu, %p)\n",
                pb, cb, pcbWritten));
    TRY
    {
        if (pcbWritten)
        {
            olChkTo(EH_BadPtr, ValidateOutBuffer(pcbWritten, sizeof(ULONG)));
        }
        olChk(ValidateHugeBuffer(pb, cb));
        olChk(Validate());
        sc = _pst->WriteAt(_psp->GetPos(), pb, cb,
                           (ULONG STACKBASED *)&cbWritten);
        olAssert(CBMAXSEEK-_psp->GetPos() >= cbWritten);
        _psp->SetPos(_psp->GetPos()+cbWritten);
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Write => %lu\n",
                cbWritten));
EH_Err:
    if (pcbWritten)
    {
        *pcbWritten = cbWritten;
        olLog(("%p::Out CExposedStream::Write().  *pcbWritten == %lu, ret = %lx\n",
               this, *pcbWritten, sc));
    }
    else
    {
        olLog(("%p::Out CExposedStream::Write().  ret == %lx\n",this, sc));
    }

EH_BadPtr:
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Seek, public
//
//  Synopsis:   Seek to a point in a stream
//
//  Arguments:  [dlibMove] - Offset to move by
//              [dwOrigin] - SEEK_SET, SEEK_CUR, SEEK_END
//              [plibNewPosition] - Return of new offset
//
//  Returns:    Appropriate status code
//
//  Modifies:   [plibNewPosition]
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Seek(LARGE_INTEGER dlibMove,
                                  DWORD dwOrigin,
                                  ULARGE_INTEGER *plibNewPosition)
{
    SCODE sc;
    LONG lMove;
    ULARGE_INTEGER ulPos;

    olLog(("%p::In  CExposedStream::Seek(%ld, %lu, %p)\n",
           this, LIGetLow(dlibMove), dwOrigin, plibNewPosition));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Seek(%ld, %lu, %p)\n",
                LIGetLow(dlibMove), dwOrigin, plibNewPosition));
    TRY
    {
        if (plibNewPosition)
        {
            olChk(ValidateOutBuffer(plibNewPosition, sizeof(ULARGE_INTEGER)));
            ULISet32(*plibNewPosition, 0);
        }
        if (dwOrigin != STREAM_SEEK_SET && dwOrigin != STREAM_SEEK_CUR &&
            dwOrigin != STREAM_SEEK_END)
            olErr(EH_Err, STG_E_INVALIDFUNCTION);

        // Truncate dlibMove to 32 bits
        if (dwOrigin == STREAM_SEEK_SET)
        {
            // Make sure we don't seek too far
            if (LIGetHigh(dlibMove) != 0)
                LISet32(dlibMove, (LONG)0xffffffff);
        }
        else
        {
            // High dword must be zero for positive values or -1 for
            // negative values
            // Additionally, for negative values, the low dword can't
            // exceed -0x80000000 because the 32nd bit is the sign
            // bit
            if (LIGetHigh(dlibMove) > 0 ||
                (LIGetHigh(dlibMove) == 0 &&
                 LIGetLow(dlibMove) >= 0x80000000))
                LISet32(dlibMove, 0x7fffffff);
            else if (LIGetHigh(dlibMove) < -1 ||
                     (LIGetHigh(dlibMove) == -1 &&
                      LIGetLow(dlibMove) <= 0x7fffffff))
                LISet32(dlibMove, (LONG)0x80000000);
        }

        lMove = (LONG)LIGetLow(dlibMove);
        olChk(Validate());
        ULISet32(ulPos, _psp->GetPos());
        switch(dwOrigin)
        {
        case STREAM_SEEK_SET:
            ULISetLow(ulPos, (ULONG)lMove);
            break;
        case STREAM_SEEK_END:
            ULONG cbSize;
            olChk(_pst->GetSize(&cbSize));
            if (lMove < 0)
            {
                if ((ULONG)(-lMove) > cbSize)
                    olErr(EH_Err, STG_E_INVALIDFUNCTION);
            }
            else if ((ULONG)lMove > CBMAXSEEK-cbSize)
                lMove = (LONG)(CBMAXSEEK-cbSize);
            ULISetLow(ulPos, cbSize+lMove);
            break;
        case STREAM_SEEK_CUR:
            if (lMove < 0)
            {
                if ((ULONG)(-lMove) > _psp->GetPos())
                    olErr(EH_Err, STG_E_INVALIDFUNCTION);
            }
            else if ((ULONG)lMove > CBMAXSEEK-_psp->GetPos())
                lMove = (LONG)(CBMAXSEEK-_psp->GetPos());
            ULISetLow(ulPos, _psp->GetPos()+lMove);
            break;
        }
        _psp->SetPos(ULIGetLow(ulPos));
        if (plibNewPosition)
            *plibNewPosition = ulPos;
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Seek => %lu\n",
                ULIGetLow(ulPos)));
EH_Err:
    olLog(("%p::Out CExposedStream::Seek().  ulPos == %lu,  ret == %lx\n",
           this, ULIGetLow(ulPos), sc));
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::SetSize, public
//
//  Synopsis:   Sets the size of a stream
//
//  Arguments:  [ulNewSize] - New size
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

STDMETHODIMP CExposedStream::SetSize(ULARGE_INTEGER ulNewSize)
{
    SCODE sc;

    olLog(("%p::In  CExposedStream::SetSize(%lu)\n",
           this, ULIGetLow(ulNewSize)));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::SetSize(%lu)\n",
                ULIGetLow(ulNewSize)));
    TRY
    {
        if (ULIGetHigh(ulNewSize) != 0)
            olErr(EH_Err, STG_E_INVALIDFUNCTION);
        olChk(Validate());
        olChk(_pst->SetSize(ULIGetLow(ulNewSize)));
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::SetSize\n"));
EH_Err:
    olLog(("%p::Out CExposedStream::SetSize().  ret == %lx\n", this, sc));
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::CopyTo, public
//
//  Synopsis:   Copies information from one stream to another
//
//  Arguments:  [pstm] - Destination
//              [cb] - Number of bytes to copy
//              [pcbRead] - Return number of bytes read
//              [pcbWritten] - Return number of bytes written
//
//  Returns:    Appropriate status code
//
//  Modifies:   [pcbRead]
//              [pcbWritten]
//
//  Notes:      We do our best to handle overlap correctly.  This allows
//              CopyTo to be used to insert and remove space within a
//              stream.
//
//              In the error case, we make no gurantees as to the
//              validity of pcbRead, pcbWritten, or either stream's
//              seek position.
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::CopyTo(IStream *pstm,
                                    ULARGE_INTEGER cb,
                                    ULARGE_INTEGER *pcbRead,
                                    ULARGE_INTEGER *pcbWritten)
{
    SCODE sc;
    ULONG ulCopySize;
    ULONG ulSrcSize;
    ULONG ulSrcOrig;
    ULARGE_INTEGER uliDestOrig;
    LARGE_INTEGER liDestPos;
    BYTE *pb = NULL;
    BOOL fOverlap;
    ULONG ulBytesCopied = 0;

    olLog(("%p::In  CExposedStream::CopyTo(%p, %lu, %p, %p)\n",
           this, pstm, ULIGetLow(cb), pcbRead, pcbWritten));
    olDebugOut((DEB_TRACE, "In  CExposedStream::CopyTo("
                "%p, %lu, %p, %p)\n", pstm, ULIGetLow(cb),
                pcbRead, pcbWritten));

    TRY
    {
        if (pcbRead)
        {
            olChk(ValidateOutBuffer(pcbRead, sizeof(ULARGE_INTEGER)));
            ULISet32(*pcbRead, 0);
        }
        if (pcbWritten)
        {
            olChk(ValidateOutBuffer(pcbWritten, sizeof(ULARGE_INTEGER)));
            ULISet32(*pcbWritten, 0);
        }

        olChk(ValidateInterface(pstm, IID_IStream));
        olChk(Validate());

        //  Bound the size of the copy
        //  1.  The maximum we can copy is 0xffffffff

        if (ULIGetHigh(cb) == 0)
            ulCopySize = ULIGetLow(cb);
        else
            ulCopySize = 0xffffffff;

        //  2.  We can only copy what's available in the source stream

        sc = _pst->GetSize(&ulSrcSize);
        olChk(sc);

        ulSrcOrig = _psp->GetPos();
        if (ulSrcSize < ulSrcOrig)
        {
            //  Nothing in source to copy
            ulCopySize = 0;
        }
        else if ((ulSrcSize - ulSrcOrig) < ulCopySize)
        {
            //  Shrink ulCopySize to fit bytes in source
            ulCopySize = ulSrcSize - ulSrcOrig;
        }

        //  3.  We can only copy what will fit in the destination

        LISet32(liDestPos, 0);
        olHChk(pstm->Seek(liDestPos, STREAM_SEEK_CUR, &uliDestOrig));
        olAssert(ULIGetHigh(uliDestOrig) == 0);

        if (ulCopySize > CBMAXSEEK - ULIGetLow(uliDestOrig))
            ulCopySize = CBMAXSEEK - ULIGetLow(uliDestOrig);

        //  We are allowed to fail here with out-of-memory
        olMem(pb = new BYTE[STREAMBUFFERSIZE]);

        // Since we have no reliable way to determine if the source and
        // destination represent the same stream, we assume they
        // do and always handle overlap.

        fOverlap = (ULIGetLow(uliDestOrig) > ulSrcOrig &&
                    ULIGetLow(uliDestOrig) < ulSrcOrig + ulCopySize);

        ULONG ulSrcCopyOffset;
        ULONG ulDstCopyOffset;
        if (fOverlap)
        {
            //  We're going to copy back to front, so determine the
            //  stream end positions
            ulSrcCopyOffset = ulSrcOrig + ulCopySize;

            //  uliDestOrig is the destination starting offset
            ulDstCopyOffset = ULIGetLow(uliDestOrig) + ulCopySize;
        }

        while (ulCopySize > 0)
        {
            //  We can only copy up to STREAMBUFFERSIZE bytes at a time
            ULONG cbPart = min(ulCopySize, STREAMBUFFERSIZE);

            if (fOverlap)
            {
                //  We're copying back to front so we need to seek to
                //  set up the streams correctly

                ulSrcCopyOffset -= cbPart;
                ulDstCopyOffset -= cbPart;

                //  Set source stream position
                _psp->SetPos(ulSrcCopyOffset);

                //  Set destination stream position
                LISet32(liDestPos, ulDstCopyOffset);
                olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
            }

            {
                ULONG ulRead;
                olHChk(Read(pb, cbPart, &ulRead));
                if (cbPart != ulRead)
                {
                    //  There was no error, but we were unable to read cbPart
                    //  bytes.  Something's wrong (the underlying ILockBytes?)
                    //  but we can't control it;  just return an error.
                    olErr(EH_Err, STG_E_READFAULT);
                }
            }


            {
                ULONG ulWritten;
                olHChk(pstm->Write(pb, cbPart, &ulWritten));
                if (cbPart != ulWritten)
                {
                    //  There was no error, but we were unable to write
                    //  ulWritten bytes.  We can't trust the pstm
                    //  implementation, so all we can do here is return
                    //  an error.
                    olErr(EH_Err, STG_E_WRITEFAULT);
                }
            }

            olAssert(ulCopySize >= cbPart);
            ulCopySize -= cbPart;
            ulBytesCopied += cbPart;
        }

        if (fOverlap)
        {
            //  Set the seek pointers to the correct location
            _psp->SetPos(ulSrcOrig + ulBytesCopied);

            LISet32(liDestPos, ULIGetLow(uliDestOrig) + ulBytesCopied);
            olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
        }

        if (pcbRead)
            ULISet32(*pcbRead, ulBytesCopied);
        if (pcbWritten)
            ULISet32(*pcbWritten, ulBytesCopied);
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::CopyTo => %lu, %lu\n",
                pcbRead ? ULIGetLow(*pcbRead) : 0,
                pcbWritten ? ULIGetLow(*pcbWritten) : 0));
    // Fall through
EH_Err:
    delete [] pb;
    olLog(("%p::Out CExposedStream::CopyTo().  "
           "cbRead == %lu, cbWritten == %lu, ret == %lx\n",
           this, pcbRead ? ULIGetLow(*pcbRead) : 0,
           pcbWritten ? ULIGetLow(*pcbWritten) : 0, sc));
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Release, public
//
//  Synopsis:   Releases a stream
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------


STDMETHODIMP_(ULONG) CExposedStream::Release(void)
{
    LONG lRet;

    olLog(("%p::In  CExposedStream::Release()\n", this));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Release()\n"));
    TRY
    {
        if (FAILED(Validate()))
            return 0;
        olAssert(_cReferences > 0);
        lRet = AtomicDec(&_cReferences);
        if (lRet == 0)
        {
            delete this;
        }
        else if (lRet < 0)
            lRet = 0;
    }
    CATCH(CException, e)
    {
        UNREFERENCED_PARM(e);
        lRet = 0;
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Release\n"));
    olLog(("%p::Out CExposedStream::Release().  ret == %lu\n", this, lRet));
    FreeLogFile();
    return lRet;
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Stat, public
//
//  Synopsis:   Fills in a buffer of information about this object
//
//  Arguments:  [pstatstg] - Buffer
//
//  Returns:    Appropriate status code
//
//  Modifies:   [pstatstg]
//
//---------------------------------------------------------------


TSTDMETHODIMP CExposedStream::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
{
    SCODE sc, scSem = STG_E_INUSE;

    olLog(("%p::In  CExposedStream::Stat(%p)\n", this, pstatstg));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Stat(%p)\n",
                pstatstg));
    TRY
    {
        olChkTo(EH_RetSc, ValidateOutBuffer(pstatstg, sizeof(STATSTGW)));
        olChk(VerifyStatFlag(grfStatFlag));
        olChk(Validate());
        olChk(_pst->Stat(pstatstg, grfStatFlag));
        pstatstg->type = STGTY_STREAM;
        pstatstg->grfLocksSupported = 0;
        pstatstg->reserved = 0;
        pstatstg->ctime.dwLowDateTime = pstatstg->ctime.dwHighDateTime = 0;
        pstatstg->mtime.dwLowDateTime = pstatstg->mtime.dwHighDateTime = 0;
        pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Stat\n"));
EH_Err:
    if (FAILED(sc))
        memset(pstatstg, 0, sizeof(STATSTGW));
EH_RetSc:
    olLog(("%p::Out CExposedStream::Stat().  ret == %lx\n",
           this, sc));
    return sc;
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Clone, public
//
//  Synopsis:   Clones a stream
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Clone(IStream **ppstm)
{
    CExposedStream *pst;
    CSeekPointer *psp;
    SCODE sc;

    olLog(("%p::In  CExposedStream::Clone(%p)\n", this, ppstm));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Clone(%p)\n", ppstm));
    TRY
    {
        olChk(ValidateOutPtrBuffer(ppstm));
        *ppstm = NULL;
        olChk(Validate());
        olChk(_pst->CheckReverted());
        olMem(psp = new CSeekPointer(_psp->GetPos()));
        olMemTo(EH_psp, pst = new CExposedStream);
        olChkTo(EH_pst, pst->Init(_pst, psp));
        _pst->vAddRef();
        *ppstm = pst;
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Clone => %p\n", *ppstm));
    return ResultFromScode(sc);

EH_pst:
    delete pst;
EH_psp:
    psp->vRelease();
EH_Err:
    olLog(("%p::Out CExposedStream::Clone().  *ppstm == %p, ret == %lx\n",
           this, *ppstm, sc));
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::AddRef, public
//
//  Synopsis:   Increments the ref count
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

STDMETHODIMP_(ULONG) CExposedStream::AddRef(void)
{
    ULONG ulRet;

    olLog(("%p::In  CExposedStream::AddRef()\n", this));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::AddRef()\n"));
    TRY
    {
        if (FAILED(Validate()))
            return 0;
        AtomicInc(&_cReferences);
        ulRet = _cReferences;
    }
    CATCH(CException, e)
    {
        UNREFERENCED_PARM(e);
        ulRet = 0;
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::AddRef\n"));
    olLog(("%p::Out CExposedStream::AddRef().  ret == %lu\n", this, ulRet));
    return ulRet;
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::LockRegion, public
//
//  Synopsis:   Nonfunctional
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

STDMETHODIMP CExposedStream::LockRegion(ULARGE_INTEGER libOffset,
                                        ULARGE_INTEGER cb,
                                        DWORD dwLockType)
{
    olDebugOut((DEB_ITRACE, "In  CExposedStream::LockRegion("
                "%lu, %lu\n", ULIGetLow(cb), dwLockType));
    olDebugOut((DEB_ITRACE, "Out CExposedStream::LockRegion\n"));
    olLog(("%p::INVALID CALL TO CExposedStream::LockRegion()\n"));
    return ResultFromScode(STG_E_INVALIDFUNCTION);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::UnlockRegion, public
//
//  Synopsis:   Nonfunctional
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------

STDMETHODIMP CExposedStream::UnlockRegion(ULARGE_INTEGER libOffset,
                                          ULARGE_INTEGER cb,
                                          DWORD dwLockType)
{
    olDebugOut((DEB_ITRACE, "In  CExposedStream::UnlockRegion(%lu, %lu)\n",
                ULIGetLow(cb), dwLockType));
    olDebugOut((DEB_ITRACE, "Out CExposedStream::UnlockRegion\n"));
    olLog(("%p::INVALID CALL TO CExposedStream::UnlockRegion()\n"));
    return ResultFromScode(STG_E_INVALIDFUNCTION);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Commit, public
//
//  Synopsis:   No-op in current implementation
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Commit(DWORD grfCommitFlags)
{
    SCODE sc, scSem = STG_E_INUSE;
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Commit(%lu)\n",
                grfCommitFlags));
    olLog(("%p::In  CExposedStream::Commit(%lx)\n", this, grfCommitFlags));

    TRY
    {
        olChk(Validate());
        olChk(_pst->Commit(grfCommitFlags));
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Commit\n"));
EH_Err:
    olLog(("%p::Out CExposedStream::Commit().  ret == %lx", this, sc));
    return ResultFromScode(sc);
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::Revert, public
//
//  Synopsis:   No-op in current implementation
//
//  Returns:    Appropriate status code
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::Revert(void)
{
    olDebugOut((DEB_ITRACE, "In  CExposedStream::Revert()\n"));
    olDebugOut((DEB_ITRACE, "Out CExposedStream::Revert\n"));
    olLog(("%p::In  CExposedStream::Revert()\n", this));
    olLog(("%p::Out CExposedStream::Revert().  ret == %lx", this, S_OK));

    return NOERROR;
}

//+--------------------------------------------------------------
//
//  Member:     CExposedStream::QueryInterface, public
//
//  Synopsis:   Returns an object for the requested interface
//
//  Arguments:  [iid] - Interface ID
//              [ppvObj] - Object return
//
//  Returns:    Appropriate status code
//
//  Modifies:   [ppvObj]
//
//---------------------------------------------------------------


STDMETHODIMP CExposedStream::QueryInterface(REFIID iid, void **ppvObj)
{
    SCODE sc;

    olLog(("%p::In  CExposedStream::QueryInterface(?, %p)\n",
           this, ppvObj));
    olDebugOut((DEB_ITRACE, "In  CExposedStream::QueryInterface(?, %p)\n",
                ppvObj));
    TRY
    {
        olChk(ValidateOutPtrBuffer(ppvObj));
        *ppvObj = NULL;
        olChk(ValidateIid(iid));
        olChk(Validate());
        olChk(_pst->CheckReverted());
        if (IsEqualIID(iid, IID_IStream) || IsEqualIID(iid, IID_IUnknown))
        {
            olChk(AddRef());
            *ppvObj = this;
        }
        else
            olErr(EH_Err, E_NOINTERFACE);
        sc = S_OK;
    }
    CATCH(CException, e)
    {
        sc = e.GetErrorCode();
    }
    END_CATCH
    olDebugOut((DEB_ITRACE, "Out CExposedStream::QueryInterface => %p\n",
                ppvObj));
EH_Err:
    olLog(("%p::Out CExposedStream::QueryInterface().  *ppvObj == %p, ret == %lx\n",
           this, *ppvObj, sc));
    return ResultFromScode(sc);
}