xref: /reactos/dll/win32/ole32/stg_stream.c (revision c0f90872)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Compound Storage (32 bit version)
3c2c66affSColin Finck  * Stream implementation
4c2c66affSColin Finck  *
5c2c66affSColin Finck  * This file contains the implementation of the stream interface
6c2c66affSColin Finck  * for streams contained in a compound storage.
7c2c66affSColin Finck  *
8c2c66affSColin Finck  * Copyright 1999 Francis Beaudet
9c2c66affSColin Finck  * Copyright 1999 Thuy Nguyen
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
12c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
13c2c66affSColin Finck  * License as published by the Free Software Foundation; either
14c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
17c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19c2c66affSColin Finck  * Lesser General Public License for more details.
20c2c66affSColin Finck  *
21c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
22c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
23c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24c2c66affSColin Finck  */
25c2c66affSColin Finck 
26*c0f90872SAmine Khaldi #include <stdlib.h>
27*c0f90872SAmine Khaldi #include <stdarg.h>
28*c0f90872SAmine Khaldi #include <stdio.h>
29*c0f90872SAmine Khaldi #include <string.h>
30*c0f90872SAmine Khaldi 
31*c0f90872SAmine Khaldi #define COBJMACROS
32*c0f90872SAmine Khaldi #define NONAMELESSUNION
33*c0f90872SAmine Khaldi 
34*c0f90872SAmine Khaldi #include "windef.h"
35*c0f90872SAmine Khaldi #include "winbase.h"
36*c0f90872SAmine Khaldi #include "winerror.h"
37*c0f90872SAmine Khaldi #include "winternl.h"
38*c0f90872SAmine Khaldi #include "wine/debug.h"
39*c0f90872SAmine Khaldi 
40c2c66affSColin Finck #include "storage32.h"
41c2c66affSColin Finck 
42c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(storage);
43c2c66affSColin Finck 
44c2c66affSColin Finck /***
45c2c66affSColin Finck  * This implements the IUnknown method QueryInterface for this
46c2c66affSColin Finck  * class
47c2c66affSColin Finck  */
StgStreamImpl_QueryInterface(IStream * iface,REFIID riid,void ** ppvObject)48c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_QueryInterface(
49c2c66affSColin Finck 		  IStream*     iface,
50c2c66affSColin Finck 		  REFIID         riid,	      /* [in] */
51c2c66affSColin Finck 		  void**         ppvObject)   /* [iid_is][out] */
52c2c66affSColin Finck {
53c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
54c2c66affSColin Finck 
55c2c66affSColin Finck   if (ppvObject==0)
56c2c66affSColin Finck     return E_INVALIDARG;
57c2c66affSColin Finck 
58c2c66affSColin Finck   *ppvObject = 0;
59c2c66affSColin Finck 
60c2c66affSColin Finck   if (IsEqualIID(&IID_IUnknown, riid) ||
61c2c66affSColin Finck       IsEqualIID(&IID_ISequentialStream, riid) ||
62c2c66affSColin Finck       IsEqualIID(&IID_IStream, riid))
63c2c66affSColin Finck   {
64c2c66affSColin Finck     *ppvObject = &This->IStream_iface;
65c2c66affSColin Finck   }
66c2c66affSColin Finck   else
67c2c66affSColin Finck     return E_NOINTERFACE;
68c2c66affSColin Finck 
69c2c66affSColin Finck   IStream_AddRef(iface);
70c2c66affSColin Finck 
71c2c66affSColin Finck   return S_OK;
72c2c66affSColin Finck }
73c2c66affSColin Finck 
74c2c66affSColin Finck /***
75c2c66affSColin Finck  * This implements the IUnknown method AddRef for this
76c2c66affSColin Finck  * class
77c2c66affSColin Finck  */
StgStreamImpl_AddRef(IStream * iface)78c2c66affSColin Finck static ULONG WINAPI StgStreamImpl_AddRef(
79c2c66affSColin Finck 		IStream* iface)
80c2c66affSColin Finck {
81c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
82c2c66affSColin Finck   return InterlockedIncrement(&This->ref);
83c2c66affSColin Finck }
84c2c66affSColin Finck 
85c2c66affSColin Finck /***
86c2c66affSColin Finck  * This implements the IUnknown method Release for this
87c2c66affSColin Finck  * class
88c2c66affSColin Finck  */
StgStreamImpl_Release(IStream * iface)89c2c66affSColin Finck static ULONG WINAPI StgStreamImpl_Release(
90c2c66affSColin Finck 		IStream* iface)
91c2c66affSColin Finck {
92c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
93c2c66affSColin Finck   ULONG ref = InterlockedDecrement(&This->ref);
94c2c66affSColin Finck 
95c2c66affSColin Finck   if (!ref)
96c2c66affSColin Finck   {
97c2c66affSColin Finck     TRACE("(%p)\n", This);
98c2c66affSColin Finck 
99c2c66affSColin Finck     /*
100c2c66affSColin Finck      * Release the reference we are holding on the parent storage.
101c2c66affSColin Finck      * IStorage_Release(&This->parentStorage->IStorage_iface);
102c2c66affSColin Finck      *
103c2c66affSColin Finck      * No, don't do this. Some apps call IStorage_Release without
104c2c66affSColin Finck      * calling IStream_Release first. If we grab a reference the
105c2c66affSColin Finck      * file is not closed, and the app fails when it tries to
106c2c66affSColin Finck      * reopen the file (Easy-PC, for example). Just inform the
107c2c66affSColin Finck      * storage that we have closed the stream
108c2c66affSColin Finck      */
109c2c66affSColin Finck 
110c2c66affSColin Finck     if (This->parentStorage)
111c2c66affSColin Finck       StorageBaseImpl_RemoveStream(This->parentStorage, This);
112c2c66affSColin Finck     This->parentStorage = 0;
113c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, This);
114c2c66affSColin Finck   }
115c2c66affSColin Finck 
116c2c66affSColin Finck   return ref;
117c2c66affSColin Finck }
118c2c66affSColin Finck 
119c2c66affSColin Finck /***
120c2c66affSColin Finck  * This method is part of the ISequentialStream interface.
121c2c66affSColin Finck  *
122c2c66affSColin Finck  * It reads a block of information from the stream at the current
123c2c66affSColin Finck  * position. It then moves the current position at the end of the
124c2c66affSColin Finck  * read block
125c2c66affSColin Finck  *
126c2c66affSColin Finck  * See the documentation of ISequentialStream for more info.
127c2c66affSColin Finck  */
StgStreamImpl_Read(IStream * iface,void * pv,ULONG cb,ULONG * pcbRead)128c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Read(
129c2c66affSColin Finck 		  IStream*     iface,
130c2c66affSColin Finck 		  void*          pv,        /* [length_is][size_is][out] */
131c2c66affSColin Finck 		  ULONG          cb,        /* [in] */
132c2c66affSColin Finck 		  ULONG*         pcbRead)   /* [out] */
133c2c66affSColin Finck {
134c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
135c2c66affSColin Finck 
136c2c66affSColin Finck   ULONG bytesReadBuffer;
137c2c66affSColin Finck   HRESULT res;
138c2c66affSColin Finck 
139c2c66affSColin Finck   TRACE("(%p, %p, %d, %p)\n",
140c2c66affSColin Finck 	iface, pv, cb, pcbRead);
141c2c66affSColin Finck 
142c2c66affSColin Finck   if (!This->parentStorage)
143c2c66affSColin Finck   {
144c2c66affSColin Finck     WARN("storage reverted\n");
145c2c66affSColin Finck     return STG_E_REVERTED;
146c2c66affSColin Finck   }
147c2c66affSColin Finck 
148c2c66affSColin Finck   /*
149c2c66affSColin Finck    * If the caller is not interested in the number of bytes read,
150c2c66affSColin Finck    * we use another buffer to avoid "if" statements in the code.
151c2c66affSColin Finck    */
152c2c66affSColin Finck   if (pcbRead==0)
153c2c66affSColin Finck     pcbRead = &bytesReadBuffer;
154c2c66affSColin Finck 
155c2c66affSColin Finck   res = StorageBaseImpl_StreamReadAt(This->parentStorage,
156c2c66affSColin Finck                                      This->dirEntry,
157c2c66affSColin Finck                                      This->currentPosition,
158c2c66affSColin Finck                                      cb,
159c2c66affSColin Finck                                      pv,
160c2c66affSColin Finck                                      pcbRead);
161c2c66affSColin Finck 
162c2c66affSColin Finck   if (SUCCEEDED(res))
163c2c66affSColin Finck   {
164c2c66affSColin Finck     /*
165c2c66affSColin Finck      * Advance the pointer for the number of positions read.
166c2c66affSColin Finck      */
167c2c66affSColin Finck     This->currentPosition.QuadPart += *pcbRead;
168c2c66affSColin Finck   }
169c2c66affSColin Finck 
170c2c66affSColin Finck   TRACE("<-- %08x\n", res);
171c2c66affSColin Finck   return res;
172c2c66affSColin Finck }
173c2c66affSColin Finck 
174c2c66affSColin Finck /***
175c2c66affSColin Finck  * This method is part of the ISequentialStream interface.
176c2c66affSColin Finck  *
177c2c66affSColin Finck  * It writes a block of information to the stream at the current
178c2c66affSColin Finck  * position. It then moves the current position at the end of the
179c2c66affSColin Finck  * written block. If the stream is too small to fit the block,
180c2c66affSColin Finck  * the stream is grown to fit.
181c2c66affSColin Finck  *
182c2c66affSColin Finck  * See the documentation of ISequentialStream for more info.
183c2c66affSColin Finck  */
StgStreamImpl_Write(IStream * iface,const void * pv,ULONG cb,ULONG * pcbWritten)184c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Write(
185c2c66affSColin Finck 	          IStream*     iface,
186c2c66affSColin Finck 		  const void*    pv,          /* [size_is][in] */
187c2c66affSColin Finck 		  ULONG          cb,          /* [in] */
188c2c66affSColin Finck 		  ULONG*         pcbWritten)  /* [out] */
189c2c66affSColin Finck {
190c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
191c2c66affSColin Finck 
192c2c66affSColin Finck   ULONG bytesWritten = 0;
193c2c66affSColin Finck   HRESULT res;
194c2c66affSColin Finck 
195c2c66affSColin Finck   TRACE("(%p, %p, %d, %p)\n",
196c2c66affSColin Finck 	iface, pv, cb, pcbWritten);
197c2c66affSColin Finck 
198c2c66affSColin Finck   /*
199c2c66affSColin Finck    * Do we have permission to write to this stream?
200c2c66affSColin Finck    */
201c2c66affSColin Finck   switch(STGM_ACCESS_MODE(This->grfMode))
202c2c66affSColin Finck   {
203c2c66affSColin Finck   case STGM_WRITE:
204c2c66affSColin Finck   case STGM_READWRITE:
205c2c66affSColin Finck       break;
206c2c66affSColin Finck   default:
207c2c66affSColin Finck       WARN("access denied by flags: 0x%x\n", STGM_ACCESS_MODE(This->grfMode));
208c2c66affSColin Finck       return STG_E_ACCESSDENIED;
209c2c66affSColin Finck   }
210c2c66affSColin Finck 
211c2c66affSColin Finck   if (!pv)
212c2c66affSColin Finck     return STG_E_INVALIDPOINTER;
213c2c66affSColin Finck 
214c2c66affSColin Finck   if (!This->parentStorage)
215c2c66affSColin Finck   {
216c2c66affSColin Finck     WARN("storage reverted\n");
217c2c66affSColin Finck     return STG_E_REVERTED;
218c2c66affSColin Finck   }
219c2c66affSColin Finck 
220c2c66affSColin Finck   /*
221c2c66affSColin Finck    * If the caller is not interested in the number of bytes written,
222c2c66affSColin Finck    * we use another buffer to avoid "if" statements in the code.
223c2c66affSColin Finck    */
224c2c66affSColin Finck   if (pcbWritten == 0)
225c2c66affSColin Finck     pcbWritten = &bytesWritten;
226c2c66affSColin Finck 
227c2c66affSColin Finck   /*
228c2c66affSColin Finck    * Initialize the out parameter
229c2c66affSColin Finck    */
230c2c66affSColin Finck   *pcbWritten = 0;
231c2c66affSColin Finck 
232c2c66affSColin Finck   if (cb == 0)
233c2c66affSColin Finck   {
234c2c66affSColin Finck     TRACE("<-- S_OK, written 0\n");
235c2c66affSColin Finck     return S_OK;
236c2c66affSColin Finck   }
237c2c66affSColin Finck 
238c2c66affSColin Finck   res = StorageBaseImpl_StreamWriteAt(This->parentStorage,
239c2c66affSColin Finck                                       This->dirEntry,
240c2c66affSColin Finck                                       This->currentPosition,
241c2c66affSColin Finck                                       cb,
242c2c66affSColin Finck                                       pv,
243c2c66affSColin Finck                                       pcbWritten);
244c2c66affSColin Finck 
245c2c66affSColin Finck   /*
246c2c66affSColin Finck    * Advance the position pointer for the number of positions written.
247c2c66affSColin Finck    */
248c2c66affSColin Finck   This->currentPosition.QuadPart += *pcbWritten;
249c2c66affSColin Finck 
250c2c66affSColin Finck   if (SUCCEEDED(res))
251c2c66affSColin Finck     res = StorageBaseImpl_Flush(This->parentStorage);
252c2c66affSColin Finck 
253c2c66affSColin Finck   TRACE("<-- %08x, written %u\n", res, *pcbWritten);
254c2c66affSColin Finck   return res;
255c2c66affSColin Finck }
256c2c66affSColin Finck 
257c2c66affSColin Finck /***
258c2c66affSColin Finck  * This method is part of the IStream interface.
259c2c66affSColin Finck  *
260c2c66affSColin Finck  * It will move the current stream pointer according to the parameters
261c2c66affSColin Finck  * given.
262c2c66affSColin Finck  *
263c2c66affSColin Finck  * See the documentation of IStream for more info.
264c2c66affSColin Finck  */
StgStreamImpl_Seek(IStream * iface,LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER * plibNewPosition)265c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Seek(
266c2c66affSColin Finck 		  IStream*      iface,
267c2c66affSColin Finck 		  LARGE_INTEGER   dlibMove,         /* [in] */
268c2c66affSColin Finck 		  DWORD           dwOrigin,         /* [in] */
269c2c66affSColin Finck 		  ULARGE_INTEGER* plibNewPosition) /* [out] */
270c2c66affSColin Finck {
271c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
272c2c66affSColin Finck 
273c2c66affSColin Finck   ULARGE_INTEGER newPosition;
274c2c66affSColin Finck   DirEntry currentEntry;
275c2c66affSColin Finck   HRESULT hr;
276c2c66affSColin Finck 
277c2c66affSColin Finck   TRACE("(%p, %d, %d, %p)\n",
278c2c66affSColin Finck 	iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
279c2c66affSColin Finck 
280c2c66affSColin Finck   /*
281c2c66affSColin Finck    * fail if the stream has no parent (as does windows)
282c2c66affSColin Finck    */
283c2c66affSColin Finck 
284c2c66affSColin Finck   if (!This->parentStorage)
285c2c66affSColin Finck   {
286c2c66affSColin Finck     WARN("storage reverted\n");
287c2c66affSColin Finck     return STG_E_REVERTED;
288c2c66affSColin Finck   }
289c2c66affSColin Finck 
290c2c66affSColin Finck   /*
291c2c66affSColin Finck    * The caller is allowed to pass in NULL as the new position return value.
292c2c66affSColin Finck    * If it happens, we assign it to a dynamic variable to avoid special cases
293c2c66affSColin Finck    * in the code below.
294c2c66affSColin Finck    */
295c2c66affSColin Finck   if (plibNewPosition == 0)
296c2c66affSColin Finck   {
297c2c66affSColin Finck     plibNewPosition = &newPosition;
298c2c66affSColin Finck   }
299c2c66affSColin Finck 
300c2c66affSColin Finck   /*
301c2c66affSColin Finck    * The file pointer is moved depending on the given "function"
302c2c66affSColin Finck    * parameter.
303c2c66affSColin Finck    */
304c2c66affSColin Finck   switch (dwOrigin)
305c2c66affSColin Finck   {
306c2c66affSColin Finck     case STREAM_SEEK_SET:
307c2c66affSColin Finck       plibNewPosition->u.HighPart = 0;
308c2c66affSColin Finck       plibNewPosition->u.LowPart  = 0;
309c2c66affSColin Finck       break;
310c2c66affSColin Finck     case STREAM_SEEK_CUR:
311c2c66affSColin Finck       *plibNewPosition = This->currentPosition;
312c2c66affSColin Finck       break;
313c2c66affSColin Finck     case STREAM_SEEK_END:
314c2c66affSColin Finck       hr = StorageBaseImpl_ReadDirEntry(This->parentStorage, This->dirEntry, &currentEntry);
315c2c66affSColin Finck       if (FAILED(hr)) return hr;
316c2c66affSColin Finck       *plibNewPosition = currentEntry.size;
317c2c66affSColin Finck       break;
318c2c66affSColin Finck     default:
319c2c66affSColin Finck       WARN("invalid dwOrigin %d\n", dwOrigin);
320c2c66affSColin Finck       return STG_E_INVALIDFUNCTION;
321c2c66affSColin Finck   }
322c2c66affSColin Finck 
323c2c66affSColin Finck   plibNewPosition->QuadPart += dlibMove.QuadPart;
324c2c66affSColin Finck 
325c2c66affSColin Finck   /*
326c2c66affSColin Finck    * tell the caller what we calculated
327c2c66affSColin Finck    */
328c2c66affSColin Finck   This->currentPosition = *plibNewPosition;
329c2c66affSColin Finck 
330c2c66affSColin Finck   return S_OK;
331c2c66affSColin Finck }
332c2c66affSColin Finck 
333c2c66affSColin Finck /***
334c2c66affSColin Finck  * This method is part of the IStream interface.
335c2c66affSColin Finck  *
336c2c66affSColin Finck  * It will change the size of a stream.
337c2c66affSColin Finck  *
338c2c66affSColin Finck  * See the documentation of IStream for more info.
339c2c66affSColin Finck  */
StgStreamImpl_SetSize(IStream * iface,ULARGE_INTEGER libNewSize)340c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_SetSize(
341c2c66affSColin Finck 				     IStream*      iface,
342c2c66affSColin Finck 				     ULARGE_INTEGER  libNewSize)   /* [in] */
343c2c66affSColin Finck {
344c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
345c2c66affSColin Finck 
346c2c66affSColin Finck   HRESULT      hr;
347c2c66affSColin Finck 
348c2c66affSColin Finck   TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart);
349c2c66affSColin Finck 
350c2c66affSColin Finck   if(!This->parentStorage)
351c2c66affSColin Finck   {
352c2c66affSColin Finck     WARN("storage reverted\n");
353c2c66affSColin Finck     return STG_E_REVERTED;
354c2c66affSColin Finck   }
355c2c66affSColin Finck 
356c2c66affSColin Finck   /*
357c2c66affSColin Finck    * As documented.
358c2c66affSColin Finck    */
359c2c66affSColin Finck   if (libNewSize.u.HighPart != 0)
360c2c66affSColin Finck   {
361c2c66affSColin Finck     WARN("invalid value for libNewSize.u.HighPart %d\n", libNewSize.u.HighPart);
362c2c66affSColin Finck     return STG_E_INVALIDFUNCTION;
363c2c66affSColin Finck   }
364c2c66affSColin Finck 
365c2c66affSColin Finck   /*
366c2c66affSColin Finck    * Do we have permission?
367c2c66affSColin Finck    */
368c2c66affSColin Finck   if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
369c2c66affSColin Finck   {
370c2c66affSColin Finck     WARN("access denied\n");
371c2c66affSColin Finck     return STG_E_ACCESSDENIED;
372c2c66affSColin Finck   }
373c2c66affSColin Finck 
374c2c66affSColin Finck   hr = StorageBaseImpl_StreamSetSize(This->parentStorage, This->dirEntry, libNewSize);
375c2c66affSColin Finck 
376c2c66affSColin Finck   if (SUCCEEDED(hr))
377c2c66affSColin Finck     hr = StorageBaseImpl_Flush(This->parentStorage);
378c2c66affSColin Finck 
379c2c66affSColin Finck   return hr;
380c2c66affSColin Finck }
381c2c66affSColin Finck 
382c2c66affSColin Finck /***
383c2c66affSColin Finck  * This method is part of the IStream interface.
384c2c66affSColin Finck  *
385c2c66affSColin Finck  * It will copy the 'cb' Bytes to 'pstm' IStream.
386c2c66affSColin Finck  *
387c2c66affSColin Finck  * See the documentation of IStream for more info.
388c2c66affSColin Finck  */
StgStreamImpl_CopyTo(IStream * iface,IStream * pstm,ULARGE_INTEGER cb,ULARGE_INTEGER * pcbRead,ULARGE_INTEGER * pcbWritten)389c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_CopyTo(
390c2c66affSColin Finck 				    IStream*      iface,
391c2c66affSColin Finck 				    IStream*      pstm,         /* [unique][in] */
392c2c66affSColin Finck 				    ULARGE_INTEGER  cb,           /* [in] */
393c2c66affSColin Finck 				    ULARGE_INTEGER* pcbRead,      /* [out] */
394c2c66affSColin Finck 				    ULARGE_INTEGER* pcbWritten)   /* [out] */
395c2c66affSColin Finck {
396c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
397c2c66affSColin Finck   HRESULT        hr = S_OK;
398c2c66affSColin Finck   BYTE           tmpBuffer[128];
399c2c66affSColin Finck   ULONG          bytesRead, bytesWritten, copySize;
400c2c66affSColin Finck   ULARGE_INTEGER totalBytesRead;
401c2c66affSColin Finck   ULARGE_INTEGER totalBytesWritten;
402c2c66affSColin Finck 
403c2c66affSColin Finck   TRACE("(%p, %p, %d, %p, %p)\n",
404c2c66affSColin Finck 	iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
405c2c66affSColin Finck 
406c2c66affSColin Finck   /*
407c2c66affSColin Finck    * Sanity check
408c2c66affSColin Finck    */
409c2c66affSColin Finck 
410c2c66affSColin Finck   if (!This->parentStorage)
411c2c66affSColin Finck   {
412c2c66affSColin Finck     WARN("storage reverted\n");
413c2c66affSColin Finck     return STG_E_REVERTED;
414c2c66affSColin Finck   }
415c2c66affSColin Finck 
416c2c66affSColin Finck   if ( pstm == 0 )
417c2c66affSColin Finck     return STG_E_INVALIDPOINTER;
418c2c66affSColin Finck 
419c2c66affSColin Finck   totalBytesRead.QuadPart = 0;
420c2c66affSColin Finck   totalBytesWritten.QuadPart = 0;
421c2c66affSColin Finck 
422c2c66affSColin Finck   while ( cb.QuadPart > 0 )
423c2c66affSColin Finck   {
424c2c66affSColin Finck     if ( cb.QuadPart >= sizeof(tmpBuffer) )
425c2c66affSColin Finck       copySize = sizeof(tmpBuffer);
426c2c66affSColin Finck     else
427c2c66affSColin Finck       copySize = cb.u.LowPart;
428c2c66affSColin Finck 
429c2c66affSColin Finck     IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
430c2c66affSColin Finck 
431c2c66affSColin Finck     totalBytesRead.QuadPart += bytesRead;
432c2c66affSColin Finck 
433c2c66affSColin Finck     IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
434c2c66affSColin Finck 
435c2c66affSColin Finck     totalBytesWritten.QuadPart += bytesWritten;
436c2c66affSColin Finck 
437c2c66affSColin Finck     /*
438c2c66affSColin Finck      * Check that read & write operations were successful
439c2c66affSColin Finck      */
440c2c66affSColin Finck     if (bytesRead != bytesWritten)
441c2c66affSColin Finck     {
442c2c66affSColin Finck       hr = STG_E_MEDIUMFULL;
443c2c66affSColin Finck       WARN("medium full\n");
444c2c66affSColin Finck       break;
445c2c66affSColin Finck     }
446c2c66affSColin Finck 
447c2c66affSColin Finck     if (bytesRead!=copySize)
448c2c66affSColin Finck       cb.QuadPart = 0;
449c2c66affSColin Finck     else
450c2c66affSColin Finck       cb.QuadPart -= bytesRead;
451c2c66affSColin Finck   }
452c2c66affSColin Finck 
453c2c66affSColin Finck   if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
454c2c66affSColin Finck   if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
455c2c66affSColin Finck 
456c2c66affSColin Finck   return hr;
457c2c66affSColin Finck }
458c2c66affSColin Finck 
459c2c66affSColin Finck /***
460c2c66affSColin Finck  * This method is part of the IStream interface.
461c2c66affSColin Finck  *
462c2c66affSColin Finck  * For streams contained in structured storages, this method
463c2c66affSColin Finck  * does nothing. This is what the documentation tells us.
464c2c66affSColin Finck  *
465c2c66affSColin Finck  * See the documentation of IStream for more info.
466c2c66affSColin Finck  */
StgStreamImpl_Commit(IStream * iface,DWORD grfCommitFlags)467c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Commit(
468c2c66affSColin Finck 		  IStream*      iface,
469c2c66affSColin Finck 		  DWORD           grfCommitFlags)  /* [in] */
470c2c66affSColin Finck {
471c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
472c2c66affSColin Finck 
473c2c66affSColin Finck   if (!This->parentStorage)
474c2c66affSColin Finck   {
475c2c66affSColin Finck     WARN("storage reverted\n");
476c2c66affSColin Finck     return STG_E_REVERTED;
477c2c66affSColin Finck   }
478c2c66affSColin Finck 
479c2c66affSColin Finck   return StorageBaseImpl_Flush(This->parentStorage);
480c2c66affSColin Finck }
481c2c66affSColin Finck 
482c2c66affSColin Finck /***
483c2c66affSColin Finck  * This method is part of the IStream interface.
484c2c66affSColin Finck  *
485c2c66affSColin Finck  * For streams contained in structured storages, this method
486c2c66affSColin Finck  * does nothing. This is what the documentation tells us.
487c2c66affSColin Finck  *
488c2c66affSColin Finck  * See the documentation of IStream for more info.
489c2c66affSColin Finck  */
StgStreamImpl_Revert(IStream * iface)490c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Revert(
491c2c66affSColin Finck 		  IStream* iface)
492c2c66affSColin Finck {
493c2c66affSColin Finck   return S_OK;
494c2c66affSColin Finck }
495c2c66affSColin Finck 
StgStreamImpl_LockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)496c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_LockRegion(
497c2c66affSColin Finck 					IStream*     iface,
498c2c66affSColin Finck 					ULARGE_INTEGER libOffset,   /* [in] */
499c2c66affSColin Finck 					ULARGE_INTEGER cb,          /* [in] */
500c2c66affSColin Finck 					DWORD          dwLockType)  /* [in] */
501c2c66affSColin Finck {
502c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
503c2c66affSColin Finck 
504c2c66affSColin Finck   if (!This->parentStorage)
505c2c66affSColin Finck   {
506c2c66affSColin Finck     WARN("storage reverted\n");
507c2c66affSColin Finck     return STG_E_REVERTED;
508c2c66affSColin Finck   }
509c2c66affSColin Finck 
510c2c66affSColin Finck   FIXME("not implemented!\n");
511c2c66affSColin Finck   return E_NOTIMPL;
512c2c66affSColin Finck }
513c2c66affSColin Finck 
StgStreamImpl_UnlockRegion(IStream * iface,ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType)514c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_UnlockRegion(
515c2c66affSColin Finck 					  IStream*     iface,
516c2c66affSColin Finck 					  ULARGE_INTEGER libOffset,   /* [in] */
517c2c66affSColin Finck 					  ULARGE_INTEGER cb,          /* [in] */
518c2c66affSColin Finck 					  DWORD          dwLockType)  /* [in] */
519c2c66affSColin Finck {
520c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
521c2c66affSColin Finck 
522c2c66affSColin Finck   if (!This->parentStorage)
523c2c66affSColin Finck   {
524c2c66affSColin Finck     WARN("storage reverted\n");
525c2c66affSColin Finck     return STG_E_REVERTED;
526c2c66affSColin Finck   }
527c2c66affSColin Finck 
528c2c66affSColin Finck   FIXME("not implemented!\n");
529c2c66affSColin Finck   return E_NOTIMPL;
530c2c66affSColin Finck }
531c2c66affSColin Finck 
532c2c66affSColin Finck /***
533c2c66affSColin Finck  * This method is part of the IStream interface.
534c2c66affSColin Finck  *
535c2c66affSColin Finck  * This method returns information about the current
536c2c66affSColin Finck  * stream.
537c2c66affSColin Finck  *
538c2c66affSColin Finck  * See the documentation of IStream for more info.
539c2c66affSColin Finck  */
StgStreamImpl_Stat(IStream * iface,STATSTG * pstatstg,DWORD grfStatFlag)540c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Stat(
541c2c66affSColin Finck 		  IStream*     iface,
542c2c66affSColin Finck 		  STATSTG*       pstatstg,     /* [out] */
543c2c66affSColin Finck 		  DWORD          grfStatFlag)  /* [in] */
544c2c66affSColin Finck {
545c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
546c2c66affSColin Finck 
547c2c66affSColin Finck   DirEntry     currentEntry;
548c2c66affSColin Finck   HRESULT      hr;
549c2c66affSColin Finck 
550c2c66affSColin Finck   TRACE("%p %p %d\n", This, pstatstg, grfStatFlag);
551c2c66affSColin Finck 
552c2c66affSColin Finck   /*
553c2c66affSColin Finck    * if stream has no parent, return STG_E_REVERTED
554c2c66affSColin Finck    */
555c2c66affSColin Finck 
556c2c66affSColin Finck   if (!This->parentStorage)
557c2c66affSColin Finck   {
558c2c66affSColin Finck     WARN("storage reverted\n");
559c2c66affSColin Finck     return STG_E_REVERTED;
560c2c66affSColin Finck   }
561c2c66affSColin Finck 
562c2c66affSColin Finck   /*
563c2c66affSColin Finck    * Read the information from the directory entry.
564c2c66affSColin Finck    */
565c2c66affSColin Finck   hr = StorageBaseImpl_ReadDirEntry(This->parentStorage,
566c2c66affSColin Finck 					     This->dirEntry,
567c2c66affSColin Finck 					     &currentEntry);
568c2c66affSColin Finck 
569c2c66affSColin Finck   if (SUCCEEDED(hr))
570c2c66affSColin Finck   {
571c2c66affSColin Finck     StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
572c2c66affSColin Finck                      pstatstg,
573c2c66affSColin Finck 				     &currentEntry,
574c2c66affSColin Finck 				     grfStatFlag);
575c2c66affSColin Finck 
576c2c66affSColin Finck     pstatstg->grfMode = This->grfMode;
577c2c66affSColin Finck 
578c2c66affSColin Finck     /* In simple create mode cbSize is the current pos */
579c2c66affSColin Finck     if((This->parentStorage->openFlags & STGM_SIMPLE) && This->parentStorage->create)
580c2c66affSColin Finck       pstatstg->cbSize = This->currentPosition;
581c2c66affSColin Finck 
582c2c66affSColin Finck     return S_OK;
583c2c66affSColin Finck   }
584c2c66affSColin Finck 
585c2c66affSColin Finck   WARN("failed to read entry\n");
586c2c66affSColin Finck   return hr;
587c2c66affSColin Finck }
588c2c66affSColin Finck 
589c2c66affSColin Finck /***
590c2c66affSColin Finck  * This method is part of the IStream interface.
591c2c66affSColin Finck  *
592c2c66affSColin Finck  * This method returns a clone of the interface that allows for
593c2c66affSColin Finck  * another seek pointer
594c2c66affSColin Finck  *
595c2c66affSColin Finck  * See the documentation of IStream for more info.
596c2c66affSColin Finck  *
597c2c66affSColin Finck  * I am not totally sure what I am doing here but I presume that this
598c2c66affSColin Finck  * should be basically as simple as creating a new stream with the same
599c2c66affSColin Finck  * parent etc and positioning its seek cursor.
600c2c66affSColin Finck  */
StgStreamImpl_Clone(IStream * iface,IStream ** ppstm)601c2c66affSColin Finck static HRESULT WINAPI StgStreamImpl_Clone(
602c2c66affSColin Finck 				   IStream*     iface,
603c2c66affSColin Finck 				   IStream**    ppstm) /* [out] */
604c2c66affSColin Finck {
605c2c66affSColin Finck   StgStreamImpl* This = impl_from_IStream(iface);
606c2c66affSColin Finck   StgStreamImpl* new_stream;
607c2c66affSColin Finck   LARGE_INTEGER seek_pos;
608c2c66affSColin Finck 
609c2c66affSColin Finck   TRACE("%p %p\n", This, ppstm);
610c2c66affSColin Finck 
611c2c66affSColin Finck   /*
612c2c66affSColin Finck    * Sanity check
613c2c66affSColin Finck    */
614c2c66affSColin Finck 
615c2c66affSColin Finck   if (!This->parentStorage)
616c2c66affSColin Finck     return STG_E_REVERTED;
617c2c66affSColin Finck 
618c2c66affSColin Finck   if ( ppstm == 0 )
619c2c66affSColin Finck     return STG_E_INVALIDPOINTER;
620c2c66affSColin Finck 
621c2c66affSColin Finck   new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->dirEntry);
622c2c66affSColin Finck 
623c2c66affSColin Finck   if (!new_stream)
624c2c66affSColin Finck     return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */
625c2c66affSColin Finck 
626c2c66affSColin Finck   *ppstm = &new_stream->IStream_iface;
627c2c66affSColin Finck   IStream_AddRef(*ppstm);
628c2c66affSColin Finck 
629c2c66affSColin Finck   seek_pos.QuadPart = This->currentPosition.QuadPart;
630c2c66affSColin Finck 
631*c0f90872SAmine Khaldi   return IStream_Seek(*ppstm, seek_pos, STREAM_SEEK_SET, NULL);
632c2c66affSColin Finck }
633c2c66affSColin Finck 
634c2c66affSColin Finck /*
635c2c66affSColin Finck  * Virtual function table for the StgStreamImpl class.
636c2c66affSColin Finck  */
637c2c66affSColin Finck static const IStreamVtbl StgStreamVtbl =
638c2c66affSColin Finck {
639c2c66affSColin Finck     StgStreamImpl_QueryInterface,
640c2c66affSColin Finck     StgStreamImpl_AddRef,
641c2c66affSColin Finck     StgStreamImpl_Release,
642c2c66affSColin Finck     StgStreamImpl_Read,
643c2c66affSColin Finck     StgStreamImpl_Write,
644c2c66affSColin Finck     StgStreamImpl_Seek,
645c2c66affSColin Finck     StgStreamImpl_SetSize,
646c2c66affSColin Finck     StgStreamImpl_CopyTo,
647c2c66affSColin Finck     StgStreamImpl_Commit,
648c2c66affSColin Finck     StgStreamImpl_Revert,
649c2c66affSColin Finck     StgStreamImpl_LockRegion,
650c2c66affSColin Finck     StgStreamImpl_UnlockRegion,
651c2c66affSColin Finck     StgStreamImpl_Stat,
652c2c66affSColin Finck     StgStreamImpl_Clone
653c2c66affSColin Finck };
654c2c66affSColin Finck 
655c2c66affSColin Finck /******************************************************************************
656c2c66affSColin Finck ** StgStreamImpl implementation
657c2c66affSColin Finck */
658c2c66affSColin Finck 
659c2c66affSColin Finck /***
660c2c66affSColin Finck  * This is the constructor for the StgStreamImpl class.
661c2c66affSColin Finck  *
662c2c66affSColin Finck  * Params:
663c2c66affSColin Finck  *    parentStorage - Pointer to the storage that contains the stream to open
664c2c66affSColin Finck  *    dirEntry      - Index of the directory entry that points to this stream.
665c2c66affSColin Finck  */
StgStreamImpl_Construct(StorageBaseImpl * parentStorage,DWORD grfMode,DirRef dirEntry)666c2c66affSColin Finck StgStreamImpl* StgStreamImpl_Construct(
667c2c66affSColin Finck 		StorageBaseImpl* parentStorage,
668c2c66affSColin Finck     DWORD            grfMode,
669c2c66affSColin Finck     DirRef           dirEntry)
670c2c66affSColin Finck {
671c2c66affSColin Finck   StgStreamImpl* newStream;
672c2c66affSColin Finck 
673c2c66affSColin Finck   newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
674c2c66affSColin Finck 
675c2c66affSColin Finck   if (newStream)
676c2c66affSColin Finck   {
677c2c66affSColin Finck     /*
678c2c66affSColin Finck      * Set-up the virtual function table and reference count.
679c2c66affSColin Finck      */
680c2c66affSColin Finck     newStream->IStream_iface.lpVtbl = &StgStreamVtbl;
681c2c66affSColin Finck     newStream->ref       = 0;
682c2c66affSColin Finck 
683c2c66affSColin Finck     newStream->parentStorage = parentStorage;
684c2c66affSColin Finck 
685c2c66affSColin Finck     /*
686c2c66affSColin Finck      * We want to nail-down the reference to the storage in case the
687c2c66affSColin Finck      * stream out-lives the storage in the client application.
688c2c66affSColin Finck      *
689c2c66affSColin Finck      * -- IStorage_AddRef(&newStream->parentStorage->IStorage_iface);
690c2c66affSColin Finck      *
691c2c66affSColin Finck      * No, don't do this. Some apps call IStorage_Release without
692c2c66affSColin Finck      * calling IStream_Release first. If we grab a reference the
693c2c66affSColin Finck      * file is not closed, and the app fails when it tries to
694c2c66affSColin Finck      * reopen the file (Easy-PC, for example)
695c2c66affSColin Finck      */
696c2c66affSColin Finck 
697c2c66affSColin Finck     newStream->grfMode = grfMode;
698c2c66affSColin Finck     newStream->dirEntry = dirEntry;
699c2c66affSColin Finck 
700c2c66affSColin Finck     /*
701c2c66affSColin Finck      * Start the stream at the beginning.
702c2c66affSColin Finck      */
703c2c66affSColin Finck     newStream->currentPosition.u.HighPart = 0;
704c2c66affSColin Finck     newStream->currentPosition.u.LowPart = 0;
705c2c66affSColin Finck 
706c2c66affSColin Finck     /* add us to the storage's list of active streams */
707c2c66affSColin Finck     StorageBaseImpl_AddStream(parentStorage, newStream);
708c2c66affSColin Finck   }
709c2c66affSColin Finck 
710c2c66affSColin Finck   return newStream;
711c2c66affSColin Finck }
712