XPSOF.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:18k
源码类别:

Windows编程

开发平台:

Visual C++

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