home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / peer.xp / xpsof.c < prev    next >
C/C++ Source or Header  |  1996-04-11  |  19KB  |  724 lines

  1. /*
  2.  -  X P S O F . C
  3.  -
  4.  *  Purpose:
  5.  *      Wraps the StreamOnFile object to add buffering of the stream.
  6.  *      The wrappered version uses an in-memory buffer, or cache, to
  7.  *      reduce the number of actual Reads and Writes to the underlying
  8.  *      stream.  The goal is, obviously, to improve performance.
  9.  *      Note: This code is not thread safe.  Also, the implementation
  10.  *      is not optimized for streams that both read and write continuously
  11.  *      because there will be too much flushing going on.
  12.  *
  13.  *  Copyright 1992-1995, Microsoft Corporation.  All Rights Reserved.
  14.  */
  15.  
  16.  
  17. #include "xppch.h"
  18. #include "xpsof.h"
  19.  
  20. /* Private support function */
  21.  
  22. HRESULT HrRewindStream(LPXPSOF, ULONG);
  23. VOID    HMemCopy(VOID HUGEP * lpvDst, VOID HUGEP * lpvSrc, ULONG cb);
  24.  
  25.  
  26. XPSOF_Vtbl VtblXPSOF =
  27. {
  28.     XPSOF_QueryInterface,
  29.     XPSOF_AddRef,
  30.     XPSOF_Release,
  31.     XPSOF_Read,
  32.     XPSOF_Write,
  33.     XPSOF_Seek,
  34.     XPSOF_SetSize,
  35.     XPSOF_CopyTo,
  36.     XPSOF_Commit,
  37.     XPSOF_Revert,
  38.     XPSOF_LockRegion,
  39.     XPSOF_UnlockRegion,
  40.     XPSOF_Stat,
  41.     XPSOF_Clone
  42. };
  43.  
  44.  
  45. /*
  46.  -  HrWrapStreamOnFile
  47.  -
  48.  *  Purpose:
  49.  *      This function takes a Stream-On-File object and wraps it.  The
  50.  *      process of wrappering involves creating a similar object,
  51.  *      allocating memory for the buffer, AddRefing the original object,
  52.  *      and returning this new object to the caller.
  53.  *
  54.  *  Parameters:
  55.  *      lpAllocBuffer           A MAPI memory allocator function
  56.  *      lpFreeBuffer            The corresponding FreeBuffer function
  57.  *      ulFlags                 XPSOF_READ, XPSOF_WRITE, or XPSOF_READWRITE
  58.  *      lpStream                The original Stream-On-File to be wrapped
  59.  *      lppWrappedStream        The new XPSOF object.
  60.  *
  61.  *  Returns:
  62.  *      HRESULT                 Indicating Success/Failure
  63.  */
  64.  
  65. STDMETHODIMP
  66. HrWrapStreamOnFile(
  67.     LPALLOCATEBUFFER    lpAllocBuffer,
  68.     LPFREEBUFFER        lpFreeBuffer,
  69.     ULONG               ulFlags,
  70.     LPSTREAM            lpStream,
  71.     LPSTREAM *          lppWrappedStream)
  72. {
  73.     SCODE sc;
  74.     LPXPSOF lpxpsof = NULL;
  75.  
  76.     /* Allocate the new Stream object */
  77.  
  78.     sc = lpAllocBuffer(sizeof(XPSOF), (LPVOID *)&lpxpsof);
  79.  
  80.     if (FAILED(sc))
  81.     {
  82.         DebugTrace("Allocation of XPSOF object failed.\n");
  83.         goto ret;
  84.     }
  85.  
  86.     /* Init the object */
  87.  
  88.     lpxpsof->lpVtbl = &VtblXPSOF;
  89.     lpxpsof->lcInit = 1;
  90.     lpxpsof->ulFlags = ulFlags;
  91.     lpxpsof->lpstrm = lpStream;
  92.     lpxpsof->lpvBuff = NULL;
  93.     lpxpsof->libBuff = 0;
  94.     lpxpsof->cbBuffMac = 0;
  95.     lpxpsof->fDirty = FALSE;
  96.     lpxpsof->FreeBuffer = lpFreeBuffer;
  97.  
  98.     /* Allocate the buffer or cache */
  99.  
  100.     sc = lpAllocBuffer(XPSOF_BUFF_MAX, (LPVOID *)&lpxpsof->lpvBuff);
  101.  
  102.     if (FAILED(sc))
  103.     {
  104.         DebugTrace("Allocation of stream buffer failed.\n");
  105.         goto ret;
  106.     }
  107.  
  108.     /* Now that we've succeeded, AddRef the original object */
  109.  
  110.     lpStream->lpVtbl->AddRef(lpStream);
  111.  
  112.     *lppWrappedStream = (LPSTREAM)lpxpsof;
  113.  
  114. ret:
  115.     if (FAILED(sc))
  116.     {
  117.         if (lpxpsof)
  118.         {
  119.             lpFreeBuffer(lpxpsof->lpvBuff);
  120.             lpFreeBuffer(lpxpsof);
  121.         }
  122.     }
  123.  
  124.     DebugTraceSc(HrWrapStreamOnFile, sc);
  125.     return ResultFromScode(sc);
  126. }
  127.  
  128.  
  129. /*
  130.  -  IUnknown::QueryInterface
  131.  -  IUnknown::AddRef
  132.  -  IUnknown::Release
  133.  -
  134.  *  Purpose:
  135.  *      These are the XPSOF's OLE IUnknown methods.
  136.  */
  137.  
  138. STDMETHODIMP
  139. XPSOF_QueryInterface(LPXPSOF lpXPSOF, REFIID riid, LPVOID * lppvObj)
  140. {
  141.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  142.         IsBadReadPtr (riid, sizeof(IID)) ||
  143.         IsBadWritePtr (lppvObj, sizeof(LPVOID)))
  144.     {
  145.         DebugTraceSc(XPSOF_QueryInterface, E_INVALIDARG);
  146.         return ResultFromScode (E_INVALIDARG);
  147.     }
  148.  
  149.     if (memcmp(riid, &IID_IUnknown, sizeof(IID))
  150.         && memcmp(riid, &IID_IStream, sizeof(IID)))
  151.     {
  152.         *lppvObj = NULL;    // OLE requires zeroing [out] parameters
  153.         DebugTraceSc(XPSOF_QueryInterface, E_NOINTERFACE);
  154.         return ResultFromScode (E_NOINTERFACE);
  155.     }
  156.  
  157.     lpXPSOF->lcInit++;
  158.     *lppvObj = lpXPSOF;
  159.  
  160.     return hrSuccess;
  161. }
  162.  
  163.  
  164. STDMETHODIMP_(ULONG)
  165. XPSOF_AddRef(LPXPSOF lpXPSOF)
  166. {
  167.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  168.     {
  169.         DebugTraceSc (XPSOF_AddRef(), E_INVALIDARG);
  170.         return 1;
  171.     }
  172.  
  173.     return ++lpXPSOF->lcInit;
  174. }
  175.  
  176.  
  177. STDMETHODIMP_(ULONG)
  178. XPSOF_Release (LPXPSOF lpXPSOF)
  179. {
  180.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  181.     {
  182.         DebugTraceSc (XPSOF_Release(), E_INVALIDARG);
  183.         return 1;
  184.     }
  185.  
  186.     if (--lpXPSOF->lcInit == 0)
  187.     {
  188.         if (lpXPSOF->lpstrm)
  189.             lpXPSOF->lpstrm->lpVtbl->Release(lpXPSOF->lpstrm);
  190.  
  191.         if (lpXPSOF->lpvBuff)
  192.             lpXPSOF->FreeBuffer(lpXPSOF->lpvBuff);
  193.  
  194.         lpXPSOF->FreeBuffer(lpXPSOF);
  195.  
  196.         return 0;
  197.     }
  198.  
  199.     return lpXPSOF->lcInit;
  200. }
  201.  
  202.  
  203. /*
  204.  -  IStream::Read
  205.  -
  206.  *  Purpose:
  207.  *      To read data from the stream.
  208.  */
  209.  
  210. STDMETHODIMP
  211. XPSOF_Read (LPXPSOF lpXPSOF,
  212.     VOID HUGEP * lpvData,
  213.     ULONG cbSize,
  214.     ULONG * lpcbRead)
  215. {
  216.     HRESULT hr = hrSuccess;
  217.     ULONG cbRead = 0;
  218.     ULONG cbT;
  219.     VOID HUGEP * lpvRead = NULL;
  220.  
  221.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  222.         IsBadHugeWritePtr (lpvData, cbSize) ||
  223.         (lpcbRead && IsBadWritePtr (lpcbRead, sizeof(ULONG))))
  224.     {
  225.         hr = ResultFromScode(STG_E_INVALIDPARAMETER);
  226.         goto ret;
  227.     }
  228.  
  229.     if (!(lpXPSOF->ulFlags & XPSOF_READ))
  230.     {
  231.         hr = ResultFromScode(STG_E_ACCESSDENIED);
  232.         goto ret;
  233.     }
  234.  
  235.     Assert(lpXPSOF->cbBuffMac >= lpXPSOF->libBuff);
  236.  
  237.     /* First, flush the buffer if it has been written into.  This     */
  238.     /* operation empties our buffer and zeros the offset and size.    */
  239.     /* We do this because we also buffer writes and we need to force  */
  240.     /* the underlying stream to point to where the caller expects.    */
  241.  
  242.     if ((lpXPSOF->ulFlags & XPSOF_WRITE) && lpXPSOF->fDirty)
  243.     {
  244.         hr = XPSOF_Commit(lpXPSOF, 0);
  245.  
  246.         if (HR_FAILED(hr))
  247.             goto ret;
  248.     }
  249.  
  250.     /* Determine if the buffer is empty (cbT == 0) or not (cbT != 0). */
  251.     /* We consider the buffer empty if we've read past the end of it  */
  252.     /* or if cbBuffMac and libBuff are equal to zero.                 */
  253.  
  254.     cbT = lpXPSOF->cbBuffMac - lpXPSOF->libBuff;
  255.  
  256.     /* If the buffer is empty and the caller wants to read less than  */
  257.     /* the size of our buffer, then we'll fill the buffer from the    */
  258.     /* underlying stream object.  Adjust our buffer offset and size.  */
  259.  
  260.     if (!cbT && (cbSize < XPSOF_BUFF_MAX))
  261.     {
  262.         hr = lpXPSOF->lpstrm->lpVtbl->Read(lpXPSOF->lpstrm,
  263.                 lpXPSOF->lpvBuff, XPSOF_BUFF_MAX, &cbRead);
  264.  
  265.         if (HR_FAILED(hr))
  266.             goto ret;
  267.  
  268.         lpXPSOF->libBuff = 0;
  269.         lpXPSOF->cbBuffMac = cbT = cbRead;
  270.     }
  271.  
  272.     /* Now, if the buffer is *not* empty and the caller wants to read */
  273.     /* fewer bytes than what is in the buffer, then we read it from   */
  274.     /* our buffer, fix-up our offset, set the count read and leave.   */
  275.  
  276.     if (cbT && (cbSize <= cbT))
  277.     {
  278.         lpvRead = (VOID HUGEP *)((LPBYTE)lpXPSOF->lpvBuff + lpXPSOF->libBuff);
  279.         HMemCopy(lpvData, lpvRead, cbSize);
  280.         lpXPSOF->libBuff += cbSize;
  281.         cbRead = cbSize;
  282.         goto ret;
  283.     }
  284.  
  285.     /* If we are here, then the caller has requested more bytes to be */
  286.     /* read than what can fit in our buffer.  In this case, we copy   */
  287.     /* the remaining data from the buffer (if any) into lpvData and   */
  288.     /* then go straight to the underlying stream for the remainder.   */
  289.     /* Either way, our buffer is empty after this operation.          */
  290.  
  291.     lpvRead = lpvData;
  292.  
  293.     if (cbT)
  294.     {
  295.         HMemCopy(lpvRead, (VOID HUGEP *)((LPBYTE)lpXPSOF->lpvBuff + lpXPSOF->libBuff), cbT);
  296.         lpvRead = (BYTE HUGEP *)lpvRead + cbT;
  297.         lpXPSOF->libBuff = 0;
  298.         lpXPSOF->cbBuffMac = 0;
  299.     }
  300.  
  301.     hr = lpXPSOF->lpstrm->lpVtbl->Read(lpXPSOF->lpstrm,
  302.             lpvRead, cbSize-cbT, &cbRead);
  303.  
  304.     if (HR_FAILED(hr))
  305.         goto ret;
  306.  
  307.     cbRead += cbT;
  308.  
  309. ret:
  310.     if (lpcbRead)
  311.         *lpcbRead = cbRead;
  312.  
  313.     DebugTraceResult (XPSOF_Read(), hr);
  314.     return hr;
  315. }
  316.  
  317.  
  318. /*
  319.  -  IStream::Write
  320.  -
  321.  *  Purpose:
  322.  *      To write data to the stream.
  323.  */
  324.  
  325. STDMETHODIMP
  326. XPSOF_Write (LPXPSOF lpXPSOF,
  327.     VOID HUGEP * lpvData,
  328.     ULONG cbSize,
  329.     ULONG * lpcbWritten)
  330. {
  331.     HRESULT hr = hrSuccess;
  332.     ULONG cbWritten = 0;
  333.     ULONG cbT;
  334.     VOID HUGEP * lpvWrite = NULL;
  335.  
  336.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  337.         IsBadHugeReadPtr (lpvData, cbSize) ||
  338.         (lpcbWritten && IsBadWritePtr (lpcbWritten, sizeof(ULONG))))
  339.     {
  340.         hr = ResultFromScode(STG_E_INVALIDPARAMETER);
  341.         goto ret;
  342.     }
  343.  
  344.     if (!(lpXPSOF->ulFlags & XPSOF_WRITE))
  345.     {
  346.         hr = ResultFromScode(STG_E_ACCESSDENIED);
  347.         goto ret;
  348.     }
  349.  
  350.     Assert(lpXPSOF->cbBuffMac >= lpXPSOF->libBuff);
  351.  
  352.     /* First, if we've been Reading, then we need to re-wind the file  */
  353.     /* pointer in the underlying stream to compensate for the last     */
  354.     /* buffered Read.  Our new vacancy = the Max Size of our buffer.   */
  355.  
  356.     if (!lpXPSOF->fDirty)
  357.     {
  358.         if (lpXPSOF->libBuff != lpXPSOF->cbBuffMac)
  359.         {
  360.             hr = HrRewindStream(lpXPSOF, lpXPSOF->cbBuffMac-lpXPSOF->libBuff);
  361.  
  362.             if (HR_FAILED(hr))
  363.                 goto ret;
  364.         }
  365.  
  366.         lpXPSOF->libBuff = 0;
  367.         lpXPSOF->cbBuffMac = XPSOF_BUFF_MAX;
  368.     }
  369.  
  370.     /* Determine the total vacancy of the buffer. */
  371.  
  372.     cbT = lpXPSOF->cbBuffMac - lpXPSOF->libBuff;
  373.  
  374.     /* If the caller wants to Write more bytes than the current  */
  375.     /* vacancy of the buffer, then commit the current buffer and */
  376.     /* Write the callers data directly to the stream.  If the    */
  377.     /* buffer is not dirty, then the Commit call is a no-op.     */
  378.  
  379.     if (cbSize > cbT)
  380.     {
  381.         hr = XPSOF_Commit(lpXPSOF, 0);
  382.  
  383.         if (HR_FAILED(hr))
  384.             goto ret;
  385.  
  386.         hr = lpXPSOF->lpstrm->lpVtbl->Write(lpXPSOF->lpstrm,
  387.                 lpvData, cbSize, &cbWritten);
  388.  
  389.         goto ret;
  390.     }
  391.  
  392.     /* The callers data will fit in our current buffer.  Copy the */
  393.     /* data into the buffer, mark the buffer as dirty, and adjust */
  394.     /* the buffer offset.  Set cbWritten to cbSize and return.    */
  395.  
  396.     lpvWrite = (VOID HUGEP *)((LPBYTE)lpXPSOF->lpvBuff + lpXPSOF->libBuff);
  397.     HMemCopy(lpvWrite, lpvData, cbSize);
  398.     lpXPSOF->fDirty = TRUE;
  399.     lpXPSOF->libBuff += cbSize;
  400.     cbWritten = cbSize;
  401.  
  402. ret:
  403.     if (lpcbWritten)
  404.         *lpcbWritten = cbWritten;
  405.  
  406.     DebugTraceResult (XPSOF_Write(), hr);
  407.     return hr;
  408. }
  409.  
  410.  
  411. /*
  412.  -  IStream::Seek
  413.  -
  414.  *  Purpose:
  415.  *      To move the file pointer in the stream.
  416.  */
  417.  
  418. STDMETHODIMP
  419. XPSOF_Seek (LPXPSOF lpXPSOF,
  420.     LARGE_INTEGER liMove,
  421.     DWORD dwMode,
  422.     ULARGE_INTEGER * lpliPos)
  423. {
  424.     HRESULT hr = hrSuccess;
  425.  
  426.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  427.         (lpliPos && IsBadWritePtr (lpliPos, sizeof(ULARGE_INTEGER))))
  428.     {
  429.         DebugTraceSc (XPSOF_Seek(), STG_E_INVALIDPARAMETER);
  430.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  431.     }
  432.  
  433.     Assert(lpXPSOF->cbBuffMac >= lpXPSOF->libBuff);
  434.  
  435.     /* If our buffer is dirty, then we've been writing into it and   */
  436.     /* we need to flush it.  Else, if it isn't dirty and our offset  */
  437.     /* and buffer size are not equal, then we've been reading and we */
  438.     /* need to rewind the underlying stream to match our position.   */
  439.  
  440.     if (lpXPSOF->fDirty)
  441.     {
  442.         hr = XPSOF_Commit(lpXPSOF, 0);
  443.  
  444.         if (HR_FAILED(hr))
  445.             goto ret;
  446.     }
  447.     else
  448.     {
  449.         if ((dwMode == STREAM_SEEK_CUR) &&
  450.             (lpXPSOF->libBuff != lpXPSOF->cbBuffMac))
  451.         {
  452.             hr = HrRewindStream(lpXPSOF, lpXPSOF->cbBuffMac-lpXPSOF->libBuff);
  453.  
  454.             if (HR_FAILED(hr))
  455.                 goto ret;
  456.         }
  457.  
  458.         lpXPSOF->libBuff = 0;
  459.         lpXPSOF->cbBuffMac = 0;
  460.     }
  461.  
  462.     /* Now, call the real streams Seek method. */
  463.  
  464.     hr = lpXPSOF->lpstrm->lpVtbl->Seek(lpXPSOF->lpstrm,
  465.             liMove, dwMode, lpliPos);
  466.  
  467. ret:
  468.     return hr;
  469. }
  470.  
  471.  
  472. /*
  473.  -  IStream::SetSize
  474.  -
  475.  *  Purpose:
  476.  *      To set a max size on the file.
  477.  */
  478.  
  479. STDMETHODIMP
  480. XPSOF_SetSize (LPXPSOF lpXPSOF, ULARGE_INTEGER liSize)
  481. {
  482.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  483.     {
  484.         DebugTraceSc (XPSOF_SetSize(), STG_E_INVALIDPARAMETER);
  485.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  486.     }
  487.  
  488.     return lpXPSOF->lpstrm->lpVtbl->SetSize(lpXPSOF->lpstrm, liSize);
  489. }
  490.  
  491.  
  492. /*
  493.  -  IStream::CopyTo
  494.  -
  495.  *  Purpose:
  496.  *      To copy data from one stream to another.
  497.  */
  498.  
  499. STDMETHODIMP
  500. XPSOF_CopyTo (LPXPSOF lpXPSOF,
  501.     LPSTREAM lpStrmDst,
  502.     ULARGE_INTEGER cbCopy,
  503.     ULARGE_INTEGER * lpcbRead,
  504.     ULARGE_INTEGER * lpcbWritten)
  505. {
  506.     HRESULT hr;
  507.  
  508.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  509.         IsBadReadPtr (lpStrmDst, sizeof(LPVOID)) ||
  510.         IsBadWritePtr (lpcbRead, sizeof(ULARGE_INTEGER)) ||
  511.         IsBadWritePtr (lpcbWritten, sizeof(ULARGE_INTEGER)))
  512.     {
  513.         DebugTraceSc (XPSOF_CopyTo(), STG_E_INVALIDPARAMETER);
  514.         return ResultFromScode(STG_E_INVALIDPARAMETER);
  515.     }
  516.  
  517.     Assert(lpXPSOF->cbBuffMac >= lpXPSOF->libBuff);
  518.  
  519.     /* If our buffer is dirty, then we've been writing into it and   */
  520.     /* we need to flush it.  Else, if it isn't dirty and our offset  */
  521.     /* and buffer size are not equal, then we've been reading and we */
  522.     /* need to rewind the underlying stream to match our position.   */
  523.  
  524.     if (lpXPSOF->fDirty)
  525.     {
  526.         hr = XPSOF_Commit(lpXPSOF, 0);
  527.  
  528.         if (HR_FAILED(hr))
  529.             goto ret;
  530.     }
  531.     else
  532.     {
  533.         if (lpXPSOF->libBuff != lpXPSOF->cbBuffMac)
  534.         {
  535.             hr = HrRewindStream(lpXPSOF, lpXPSOF->cbBuffMac-lpXPSOF->libBuff);
  536.  
  537.             if (HR_FAILED(hr))
  538.                 goto ret;
  539.         }
  540.  
  541.         lpXPSOF->libBuff = 0;
  542.         lpXPSOF->cbBuffMac = 0;
  543.     }
  544.  
  545.     /* Now, call the real streams CopyTo method. */
  546.  
  547.     hr = lpXPSOF->lpstrm->lpVtbl->CopyTo(lpXPSOF->lpstrm, lpStrmDst,
  548.             cbCopy, lpcbRead, lpcbWritten);
  549.  
  550. ret:
  551.     return hr;
  552. }
  553.  
  554.  
  555. /*
  556.  -  IStream::Commit
  557.  -
  558.  *  Purpose:
  559.  *      To force a write to disk of any data that is buffered
  560.  *      by either this object or the operating system.
  561.  */
  562.  
  563. STDMETHODIMP
  564. XPSOF_Commit (LPXPSOF lpXPSOF, ULONG ulFlags)
  565. {
  566.     HRESULT hr;
  567.  
  568.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  569.     {
  570.         DebugTraceSc (XPSOF_Commit(), STG_E_INVALIDPARAMETER);
  571.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  572.     }
  573.  
  574.     /* Flush my internal buffer if it is dirty. */
  575.  
  576.     if ((lpXPSOF->ulFlags & XPSOF_WRITE) && (lpXPSOF->fDirty))
  577.     {
  578.         hr = lpXPSOF->lpstrm->lpVtbl->Write(lpXPSOF->lpstrm,
  579.                 lpXPSOF->lpvBuff, lpXPSOF->libBuff, NULL);
  580.  
  581.         if (HR_FAILED(hr))
  582.             goto ret;
  583.     }
  584.  
  585.     /* Call Commit on the underlying stream. */
  586.  
  587.     hr = lpXPSOF->lpstrm->lpVtbl->Commit(lpXPSOF->lpstrm, ulFlags);
  588.  
  589.     /* Mark my buffer as empty cal clean. */
  590.  
  591.     lpXPSOF->fDirty = FALSE;
  592.     lpXPSOF->libBuff = 0;
  593.     lpXPSOF->cbBuffMac = 0;
  594.  
  595. ret:
  596.     return hr;
  597. }
  598.  
  599.  
  600. /*
  601.  -  IStream::Stat
  602.  -
  603.  *  Purpose:
  604.  *      To retrieve information about the stream.
  605.  */
  606.  
  607. STDMETHODIMP
  608. XPSOF_Stat (LPXPSOF lpXPSOF, STATSTG * lpStg, DWORD dwFlags)
  609. {
  610.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)) ||
  611.         IsBadWritePtr (lpStg, sizeof(STATSTG)))
  612.     {
  613.         DebugTraceSc (XPSOF_Stat(), STG_E_INVALIDPARAMETER);
  614.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  615.     }
  616.  
  617.     return lpXPSOF->lpstrm->lpVtbl->Stat(lpXPSOF->lpstrm, lpStg, dwFlags);
  618. }
  619.  
  620.  
  621. /*
  622.  -  HrRewindStream
  623.  -
  624.  *  Purpose:
  625.  *      This gets called to back-up the file pointer when a Write operation
  626.  *      follows a Read operation.  This is necessary because the file pointer
  627.  *      is actually further ahead in the file than the buffered file pointer.
  628.  *
  629.  *  Parameters:
  630.  *      lpXPSOF             - Our wrapped stream-on-file object
  631.  *      ib                  - Number of bytes to rewind
  632.  *
  633.  *  Returns:
  634.  *      hr                  - Result of the underlying Seek() call
  635.  */
  636.  
  637. HRESULT HrRewindStream(LPXPSOF lpXPSOF, ULONG ib)
  638. {
  639.     LARGE_INTEGER liRewind;
  640.  
  641.     if (!ib)
  642.         return hrSuccess;
  643.  
  644.     liRewind.HighPart = 0xFFFFFFFF;
  645.     liRewind.LowPart = -((LONG)ib);
  646.  
  647.     return lpXPSOF->lpstrm->lpVtbl->Seek(lpXPSOF->lpstrm,
  648.             liRewind, STREAM_SEEK_CUR, NULL);
  649. }
  650.  
  651.  
  652. /* Unimplemented methods; call straight through to the underlying stream. */
  653.  
  654. STDMETHODIMP
  655. XPSOF_Revert (LPXPSOF lpXPSOF)
  656. {
  657.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  658.     {
  659.         DebugTraceSc (XPSOF_Revert(), STG_E_INVALIDPARAMETER);
  660.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  661.     }
  662.  
  663.     return lpXPSOF->lpstrm->lpVtbl->Revert(lpXPSOF->lpstrm);
  664. }
  665.  
  666. STDMETHODIMP
  667. XPSOF_LockRegion (LPXPSOF lpXPSOF,
  668.     ULARGE_INTEGER uliOffset,
  669.     ULARGE_INTEGER uliSize,
  670.     DWORD dwLockType)
  671. {
  672.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  673.     {
  674.         DebugTraceSc (XPSOF_LockRegion(), STG_E_INVALIDPARAMETER);
  675.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  676.     }
  677.  
  678.     return lpXPSOF->lpstrm->lpVtbl->LockRegion(lpXPSOF->lpstrm,
  679.             uliOffset, uliSize, dwLockType);
  680. }
  681.  
  682. STDMETHODIMP
  683. XPSOF_UnlockRegion (LPXPSOF lpXPSOF,
  684.     ULARGE_INTEGER uliOffset,
  685.     ULARGE_INTEGER uliSize,
  686.     DWORD dwLockType)
  687. {
  688.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  689.     {
  690.         DebugTraceSc (XPSOF_UnlockRegion(), STG_E_INVALIDPARAMETER);
  691.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  692.     }
  693.  
  694.     return lpXPSOF->lpstrm->lpVtbl->UnlockRegion(lpXPSOF->lpstrm,
  695.             uliOffset, uliSize, dwLockType);
  696. }
  697.  
  698. STDMETHODIMP
  699. XPSOF_Clone (LPXPSOF lpXPSOF, LPSTREAM * lppStm)
  700. {
  701.     if (IsBadWritePtr (lpXPSOF, sizeof(XPSOF)))
  702.     {
  703.         DebugTraceSc (XPSOF_Clone(), STG_E_INVALIDPARAMETER);
  704.         return ResultFromScode (STG_E_INVALIDPARAMETER);
  705.     }
  706.  
  707.     return lpXPSOF->lpstrm->lpVtbl->Clone(lpXPSOF->lpstrm, lppStm);
  708. }
  709.  
  710.  
  711. /*
  712.  -  HMemCopy
  713.  -
  714.  *  Purpose:
  715.  *      Same as memcpy but works with huge pointers.
  716.  */
  717.  
  718. VOID
  719. HMemCopy(VOID HUGEP * lpvDst, VOID HUGEP * lpvSrc, ULONG cb)
  720. {
  721.     while (cb--)
  722.         *((BYTE HUGEP *)lpvDst)++ = *((BYTE HUGEP *)lpvSrc)++;
  723. }
  724.