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, ¤tEntry);
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 ¤tEntry);
568c2c66affSColin Finck
569c2c66affSColin Finck if (SUCCEEDED(hr))
570c2c66affSColin Finck {
571c2c66affSColin Finck StorageUtl_CopyDirEntryToSTATSTG(This->parentStorage,
572c2c66affSColin Finck pstatstg,
573c2c66affSColin Finck ¤tEntry,
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