ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

hglobalstream.c
Go to the documentation of this file.
00001 /*
00002  * HGLOBAL Stream implementation
00003  *
00004  * This file contains the implementation of the stream interface
00005  * for streams contained supported by an HGLOBAL pointer.
00006  *
00007  * Copyright 1999 Francis Beaudet
00008  *
00009  * This library is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU Lesser General Public
00011  * License as published by the Free Software Foundation; either
00012  * version 2.1 of the License, or (at your option) any later version.
00013  *
00014  * This library is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00022  */
00023 
00024 #include "config.h"
00025 
00026 #include <assert.h>
00027 #include <stdlib.h>
00028 #include <stdarg.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 
00032 #define COBJMACROS
00033 #define NONAMELESSUNION
00034 #define NONAMELESSSTRUCT
00035 
00036 #include "windef.h"
00037 #include "winbase.h"
00038 #include "winuser.h"
00039 #include "objbase.h"
00040 #include "ole2.h"
00041 #include "winerror.h"
00042 #include "winternl.h"
00043 
00044 #include "wine/debug.h"
00045 
00046 WINE_DEFAULT_DEBUG_CHANNEL(storage);
00047 
00048 /****************************************************************************
00049  * HGLOBALStreamImpl definition.
00050  *
00051  * This class implements the IStream interface and represents a stream
00052  * supported by an HGLOBAL pointer.
00053  */
00054 typedef struct
00055 {
00056   IStream IStream_iface;
00057   LONG ref;
00058 
00059   /* support for the stream */
00060   HGLOBAL supportHandle;
00061 
00062   /* if TRUE the HGLOBAL is destroyed when the stream is finally released */
00063   BOOL deleteOnRelease;
00064 
00065   /* size of the stream */
00066   ULARGE_INTEGER streamSize;
00067 
00068   /* current position of the cursor */
00069   ULARGE_INTEGER currentPosition;
00070 } HGLOBALStreamImpl;
00071 
00072 static inline HGLOBALStreamImpl *impl_from_IStream(IStream *iface)
00073 {
00074   return CONTAINING_RECORD(iface, HGLOBALStreamImpl, IStream_iface);
00075 }
00076 
00077 static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
00078           IStream*     iface,
00079           REFIID         riid,        /* [in] */
00080           void**         ppvObject)   /* [iid_is][out] */
00081 {
00082   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00083 
00084   if (ppvObject==0)
00085     return E_INVALIDARG;
00086 
00087   *ppvObject = 0;
00088 
00089   if (IsEqualIID(&IID_IUnknown, riid) ||
00090       IsEqualIID(&IID_ISequentialStream, riid) ||
00091       IsEqualIID(&IID_IStream, riid))
00092   {
00093     *ppvObject = This;
00094   }
00095 
00096   if ((*ppvObject)==0)
00097     return E_NOINTERFACE;
00098 
00099   IStream_AddRef(iface);
00100 
00101   return S_OK;
00102 }
00103 
00104 static ULONG WINAPI HGLOBALStreamImpl_AddRef(IStream* iface)
00105 {
00106   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00107   return InterlockedIncrement(&This->ref);
00108 }
00109 
00110 static ULONG WINAPI HGLOBALStreamImpl_Release(
00111         IStream* iface)
00112 {
00113   HGLOBALStreamImpl* This= impl_from_IStream(iface);
00114   ULONG ref = InterlockedDecrement(&This->ref);
00115 
00116   if (!ref)
00117   {
00118     if (This->deleteOnRelease)
00119     {
00120       GlobalFree(This->supportHandle);
00121       This->supportHandle = NULL;
00122     }
00123 
00124     HeapFree(GetProcessHeap(), 0, This);
00125   }
00126 
00127   return ref;
00128 }
00129 
00130 /***
00131  * This method is part of the ISequentialStream interface.
00132  *
00133  * If reads a block of information from the stream at the current
00134  * position. It then moves the current position at the end of the
00135  * read block
00136  *
00137  * See the documentation of ISequentialStream for more info.
00138  */
00139 static HRESULT WINAPI HGLOBALStreamImpl_Read(
00140           IStream*     iface,
00141           void*          pv,        /* [length_is][size_is][out] */
00142           ULONG          cb,        /* [in] */
00143           ULONG*         pcbRead)   /* [out] */
00144 {
00145   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00146 
00147   void* supportBuffer;
00148   ULONG bytesReadBuffer;
00149   ULONG bytesToReadFromBuffer;
00150 
00151   TRACE("(%p, %p, %d, %p)\n", iface,
00152     pv, cb, pcbRead);
00153 
00154   /*
00155    * If the caller is not interested in the number of bytes read,
00156    * we use another buffer to avoid "if" statements in the code.
00157    */
00158   if (pcbRead==0)
00159     pcbRead = &bytesReadBuffer;
00160 
00161   /*
00162    * Using the known size of the stream, calculate the number of bytes
00163    * to read from the block chain
00164    */
00165   bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb);
00166 
00167   /*
00168    * Lock the buffer in position and copy the data.
00169    */
00170   supportBuffer = GlobalLock(This->supportHandle);
00171   if (!supportBuffer)
00172   {
00173       WARN("read from invalid hglobal %p\n", This->supportHandle);
00174       *pcbRead = 0;
00175       return S_OK;
00176   }
00177 
00178   memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer);
00179 
00180   /*
00181    * Move the current position to the new position
00182    */
00183   This->currentPosition.u.LowPart+=bytesToReadFromBuffer;
00184 
00185   /*
00186    * Return the number of bytes read.
00187    */
00188   *pcbRead = bytesToReadFromBuffer;
00189 
00190   /*
00191    * Cleanup
00192    */
00193   GlobalUnlock(This->supportHandle);
00194 
00195   /*
00196    * Always returns S_OK even if the end of the stream is reached before the
00197    * buffer is filled
00198    */
00199 
00200   return S_OK;
00201 }
00202 
00203 /***
00204  * This method is part of the ISequentialStream interface.
00205  *
00206  * It writes a block of information to the stream at the current
00207  * position. It then moves the current position at the end of the
00208  * written block. If the stream is too small to fit the block,
00209  * the stream is grown to fit.
00210  *
00211  * See the documentation of ISequentialStream for more info.
00212  */
00213 static HRESULT WINAPI HGLOBALStreamImpl_Write(
00214               IStream*     iface,
00215           const void*    pv,          /* [size_is][in] */
00216           ULONG          cb,          /* [in] */
00217           ULONG*         pcbWritten)  /* [out] */
00218 {
00219   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00220 
00221   void*          supportBuffer;
00222   ULARGE_INTEGER newSize;
00223   ULONG          bytesWritten = 0;
00224 
00225   TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten);
00226 
00227   /*
00228    * If the caller is not interested in the number of bytes written,
00229    * we use another buffer to avoid "if" statements in the code.
00230    */
00231   if (pcbWritten == 0)
00232     pcbWritten = &bytesWritten;
00233 
00234   if (cb == 0)
00235     goto out;
00236 
00237   *pcbWritten = 0;
00238 
00239   newSize.u.HighPart = 0;
00240   newSize.u.LowPart = This->currentPosition.u.LowPart + cb;
00241 
00242   /*
00243    * Verify if we need to grow the stream
00244    */
00245   if (newSize.u.LowPart > This->streamSize.u.LowPart)
00246   {
00247     /* grow stream */
00248     HRESULT hr = IStream_SetSize(iface, newSize);
00249     if (FAILED(hr))
00250     {
00251       ERR("IStream_SetSize failed with error 0x%08x\n", hr);
00252       return hr;
00253     }
00254   }
00255 
00256   /*
00257    * Lock the buffer in position and copy the data.
00258    */
00259   supportBuffer = GlobalLock(This->supportHandle);
00260   if (!supportBuffer)
00261   {
00262       WARN("write to invalid hglobal %p\n", This->supportHandle);
00263       return S_OK;
00264   }
00265 
00266   memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb);
00267 
00268   /*
00269    * Move the current position to the new position
00270    */
00271   This->currentPosition.u.LowPart+=cb;
00272 
00273   /*
00274    * Cleanup
00275    */
00276   GlobalUnlock(This->supportHandle);
00277 
00278 out:
00279   /*
00280    * Return the number of bytes read.
00281    */
00282   *pcbWritten = cb;
00283 
00284   return S_OK;
00285 }
00286 
00287 /***
00288  * This method is part of the IStream interface.
00289  *
00290  * It will move the current stream pointer according to the parameters
00291  * given.
00292  *
00293  * See the documentation of IStream for more info.
00294  */
00295 static HRESULT WINAPI HGLOBALStreamImpl_Seek(
00296           IStream*      iface,
00297           LARGE_INTEGER   dlibMove,         /* [in] */
00298           DWORD           dwOrigin,         /* [in] */
00299           ULARGE_INTEGER* plibNewPosition) /* [out] */
00300 {
00301   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00302 
00303   ULARGE_INTEGER newPosition = This->currentPosition;
00304   HRESULT hr = S_OK;
00305 
00306   TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart,
00307     dlibMove.u.LowPart, dwOrigin, plibNewPosition);
00308 
00309   /*
00310    * The file pointer is moved depending on the given "function"
00311    * parameter.
00312    */
00313   switch (dwOrigin)
00314   {
00315     case STREAM_SEEK_SET:
00316       newPosition.u.HighPart = 0;
00317       newPosition.u.LowPart = 0;
00318       break;
00319     case STREAM_SEEK_CUR:
00320       break;
00321     case STREAM_SEEK_END:
00322       newPosition = This->streamSize;
00323       break;
00324     default:
00325       hr = STG_E_SEEKERROR;
00326       goto end;
00327   }
00328 
00329   /*
00330    * Move the actual file pointer
00331    * If the file pointer ends-up after the end of the stream, the next Write operation will
00332    * make the file larger. This is how it is documented.
00333    */
00334   newPosition.u.HighPart = 0;
00335   newPosition.u.LowPart += dlibMove.QuadPart;
00336 
00337   if (dlibMove.u.LowPart >= 0x80000000 &&
00338       newPosition.u.LowPart >= dlibMove.u.LowPart)
00339   {
00340     /* We tried to seek backwards and went past the start. */
00341     hr = STG_E_SEEKERROR;
00342     goto end;
00343   }
00344 
00345   This->currentPosition = newPosition;
00346 
00347 end:
00348   if (plibNewPosition) *plibNewPosition = This->currentPosition;
00349 
00350   return hr;
00351 }
00352 
00353 /***
00354  * This method is part of the IStream interface.
00355  *
00356  * It will change the size of a stream.
00357  *
00358  * TODO: Switch from small blocks to big blocks and vice versa.
00359  *
00360  * See the documentation of IStream for more info.
00361  */
00362 static HRESULT WINAPI HGLOBALStreamImpl_SetSize(
00363                      IStream*      iface,
00364                      ULARGE_INTEGER  libNewSize)   /* [in] */
00365 {
00366   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00367   HGLOBAL supportHandle;
00368 
00369   TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
00370 
00371   /*
00372    * HighPart is ignored as shown in tests
00373    */
00374 
00375   if (This->streamSize.u.LowPart == libNewSize.u.LowPart)
00376     return S_OK;
00377 
00378   /*
00379    * Re allocate the HGlobal to fit the new size of the stream.
00380    */
00381   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
00382 
00383   if (supportHandle == 0)
00384     return E_OUTOFMEMORY;
00385 
00386   This->supportHandle = supportHandle;
00387   This->streamSize.u.LowPart = libNewSize.u.LowPart;
00388 
00389   return S_OK;
00390 }
00391 
00392 /***
00393  * This method is part of the IStream interface.
00394  *
00395  * It will copy the 'cb' Bytes to 'pstm' IStream.
00396  *
00397  * See the documentation of IStream for more info.
00398  */
00399 static HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
00400                     IStream*      iface,
00401                     IStream*      pstm,         /* [unique][in] */
00402                     ULARGE_INTEGER  cb,           /* [in] */
00403                     ULARGE_INTEGER* pcbRead,      /* [out] */
00404                     ULARGE_INTEGER* pcbWritten)   /* [out] */
00405 {
00406   HRESULT        hr = S_OK;
00407   BYTE           tmpBuffer[128];
00408   ULONG          bytesRead, bytesWritten, copySize;
00409   ULARGE_INTEGER totalBytesRead;
00410   ULARGE_INTEGER totalBytesWritten;
00411 
00412   TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm,
00413     cb.u.LowPart, pcbRead, pcbWritten);
00414 
00415   if ( pstm == 0 )
00416     return STG_E_INVALIDPOINTER;
00417 
00418   totalBytesRead.QuadPart = 0;
00419   totalBytesWritten.QuadPart = 0;
00420 
00421   while ( cb.QuadPart > 0 )
00422   {
00423     if ( cb.QuadPart >= sizeof(tmpBuffer) )
00424       copySize = sizeof(tmpBuffer);
00425     else
00426       copySize = cb.u.LowPart;
00427 
00428     hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
00429     if (FAILED(hr))
00430         break;
00431 
00432     totalBytesRead.QuadPart += bytesRead;
00433 
00434     if (bytesRead)
00435     {
00436         hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
00437         if (FAILED(hr))
00438             break;
00439 
00440         totalBytesWritten.QuadPart += bytesWritten;
00441     }
00442 
00443     if (bytesRead!=copySize)
00444       cb.QuadPart = 0;
00445     else
00446       cb.QuadPart -= bytesRead;
00447   }
00448 
00449   if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
00450   if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
00451 
00452   return hr;
00453 }
00454 
00455 /***
00456  * This method is part of the IStream interface.
00457  *
00458  * For streams supported by HGLOBALS, this function does nothing.
00459  * This is what the documentation tells us.
00460  *
00461  * See the documentation of IStream for more info.
00462  */
00463 static HRESULT WINAPI HGLOBALStreamImpl_Commit(
00464           IStream*      iface,
00465           DWORD         grfCommitFlags)  /* [in] */
00466 {
00467   return S_OK;
00468 }
00469 
00470 /***
00471  * This method is part of the IStream interface.
00472  *
00473  * For streams supported by HGLOBALS, this function does nothing.
00474  * This is what the documentation tells us.
00475  *
00476  * See the documentation of IStream for more info.
00477  */
00478 static HRESULT WINAPI HGLOBALStreamImpl_Revert(
00479           IStream* iface)
00480 {
00481   return S_OK;
00482 }
00483 
00484 /***
00485  * This method is part of the IStream interface.
00486  *
00487  * For streams supported by HGLOBALS, this function does nothing.
00488  * This is what the documentation tells us.
00489  *
00490  * See the documentation of IStream for more info.
00491  */
00492 static HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
00493           IStream*       iface,
00494           ULARGE_INTEGER libOffset,   /* [in] */
00495           ULARGE_INTEGER cb,          /* [in] */
00496           DWORD          dwLockType)  /* [in] */
00497 {
00498   return STG_E_INVALIDFUNCTION;
00499 }
00500 
00501 /*
00502  * This method is part of the IStream interface.
00503  *
00504  * For streams supported by HGLOBALS, this function does nothing.
00505  * This is what the documentation tells us.
00506  *
00507  * See the documentation of IStream for more info.
00508  */
00509 static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
00510           IStream*       iface,
00511           ULARGE_INTEGER libOffset,   /* [in] */
00512           ULARGE_INTEGER cb,          /* [in] */
00513           DWORD          dwLockType)  /* [in] */
00514 {
00515   return S_OK;
00516 }
00517 
00518 /***
00519  * This method is part of the IStream interface.
00520  *
00521  * This method returns information about the current
00522  * stream.
00523  *
00524  * See the documentation of IStream for more info.
00525  */
00526 static HRESULT WINAPI HGLOBALStreamImpl_Stat(
00527           IStream*     iface,
00528           STATSTG*     pstatstg,     /* [out] */
00529           DWORD        grfStatFlag)  /* [in] */
00530 {
00531   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00532 
00533   memset(pstatstg, 0, sizeof(STATSTG));
00534 
00535   pstatstg->pwcsName = NULL;
00536   pstatstg->type     = STGTY_STREAM;
00537   pstatstg->cbSize   = This->streamSize;
00538 
00539   return S_OK;
00540 }
00541 
00542 static HRESULT WINAPI HGLOBALStreamImpl_Clone(
00543           IStream*     iface,
00544           IStream**    ppstm) /* [out] */
00545 {
00546   HGLOBALStreamImpl* This = impl_from_IStream(iface);
00547   ULARGE_INTEGER dummy;
00548   LARGE_INTEGER offset;
00549   HRESULT hr;
00550 
00551   TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart);
00552   hr = CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm);
00553   if(FAILED(hr))
00554     return hr;
00555   offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart;
00556   IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
00557   return S_OK;
00558 }
00559 
00560 static const IStreamVtbl HGLOBALStreamImplVtbl =
00561 {
00562     HGLOBALStreamImpl_QueryInterface,
00563     HGLOBALStreamImpl_AddRef,
00564     HGLOBALStreamImpl_Release,
00565     HGLOBALStreamImpl_Read,
00566     HGLOBALStreamImpl_Write,
00567     HGLOBALStreamImpl_Seek,
00568     HGLOBALStreamImpl_SetSize,
00569     HGLOBALStreamImpl_CopyTo,
00570     HGLOBALStreamImpl_Commit,
00571     HGLOBALStreamImpl_Revert,
00572     HGLOBALStreamImpl_LockRegion,
00573     HGLOBALStreamImpl_UnlockRegion,
00574     HGLOBALStreamImpl_Stat,
00575     HGLOBALStreamImpl_Clone
00576 };
00577 
00578 /***********************************************************************
00579  *           CreateStreamOnHGlobal     [OLE32.@]
00580  */
00581 HRESULT WINAPI CreateStreamOnHGlobal(
00582         HGLOBAL   hGlobal,
00583         BOOL      fDeleteOnRelease,
00584         LPSTREAM* ppstm)
00585 {
00586   HGLOBALStreamImpl* This;
00587 
00588   if (!ppstm)
00589     return E_INVALIDARG;
00590 
00591   This = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
00592   if (!This) return E_OUTOFMEMORY;
00593 
00594   This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl;
00595   This->ref = 1;
00596 
00597   /* initialize the support */
00598   This->supportHandle = hGlobal;
00599   This->deleteOnRelease = fDeleteOnRelease;
00600 
00601   /* allocate a handle if one is not supplied */
00602   if (!This->supportHandle)
00603     This->supportHandle = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE, 0);
00604 
00605   /* start at the beginning */
00606   This->currentPosition.u.HighPart = 0;
00607   This->currentPosition.u.LowPart = 0;
00608 
00609   /* initialize the size of the stream to the size of the handle */
00610   This->streamSize.u.HighPart = 0;
00611   This->streamSize.u.LowPart = GlobalSize(This->supportHandle);
00612 
00613   *ppstm = &This->IStream_iface;
00614 
00615   return S_OK;
00616 }
00617 
00618 /***********************************************************************
00619  *           GetHGlobalFromStream     [OLE32.@]
00620  */
00621 HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
00622 {
00623   HGLOBALStreamImpl* pStream;
00624 
00625   if (pstm == NULL)
00626     return E_INVALIDARG;
00627 
00628   pStream = (HGLOBALStreamImpl*) pstm;
00629 
00630   /*
00631    * Verify that the stream object was created with CreateStreamOnHGlobal.
00632    */
00633   if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl)
00634     *phglobal = pStream->supportHandle;
00635   else
00636   {
00637     *phglobal = 0;
00638     return E_INVALIDARG;
00639   }
00640 
00641   return S_OK;
00642 }

Generated on Sat May 26 2012 04:24:09 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.