include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / combase / hglobalstream.c
blob88491f24e879a527f392829e08c944c4577b50bd
1 /*
2 * HGLOBAL Stream implementation
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2016 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #include "objbase.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(storage);
29 struct handle_wrapper
31 LONG ref;
32 HGLOBAL hglobal;
33 ULONG size;
34 BOOL delete_on_release;
37 static void handle_addref(struct handle_wrapper *handle)
39 InterlockedIncrement(&handle->ref);
42 static void handle_release(struct handle_wrapper *handle)
44 ULONG ref = InterlockedDecrement(&handle->ref);
46 if (!ref)
48 if (handle->delete_on_release) GlobalFree(handle->hglobal);
49 free(handle);
53 static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
55 struct handle_wrapper *handle;
57 handle = malloc(sizeof(*handle));
58 if (!handle) return NULL;
60 /* allocate a handle if one is not supplied */
61 if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0);
62 if (!hglobal)
64 free(handle);
65 return NULL;
67 handle->ref = 1;
68 handle->hglobal = hglobal;
69 handle->size = GlobalSize(hglobal);
70 handle->delete_on_release = delete_on_release;
72 return handle;
75 struct hglobal_stream
77 IStream IStream_iface;
78 LONG ref;
80 struct handle_wrapper *handle;
81 ULARGE_INTEGER position;
84 static inline struct hglobal_stream *impl_from_IStream(IStream *iface)
86 return CONTAINING_RECORD(iface, struct hglobal_stream, IStream_iface);
89 static const IStreamVtbl hglobalstreamvtbl;
91 static struct hglobal_stream *hglobalstream_construct(void)
93 struct hglobal_stream *object = calloc(1, sizeof(*object));
95 if (object)
97 object->IStream_iface.lpVtbl = &hglobalstreamvtbl;
98 object->ref = 1;
100 return object;
103 static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj)
105 if (!obj)
106 return E_INVALIDARG;
108 if (IsEqualIID(&IID_IUnknown, riid) ||
109 IsEqualIID(&IID_ISequentialStream, riid) ||
110 IsEqualIID(&IID_IStream, riid))
112 *obj = iface;
113 IStream_AddRef(iface);
114 return S_OK;
117 *obj = NULL;
118 return E_NOINTERFACE;
121 static ULONG WINAPI stream_AddRef(IStream *iface)
123 struct hglobal_stream *stream = impl_from_IStream(iface);
124 return InterlockedIncrement(&stream->ref);
127 static ULONG WINAPI stream_Release(IStream *iface)
129 struct hglobal_stream *stream = impl_from_IStream(iface);
130 ULONG ref = InterlockedDecrement(&stream->ref);
132 if (!ref)
134 handle_release(stream->handle);
135 free(stream);
138 return ref;
141 static HRESULT WINAPI stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *read_len)
143 struct hglobal_stream *stream = impl_from_IStream(iface);
144 ULONG dummy, len;
145 char *buffer;
147 TRACE("%p, %p, %ld, %p\n", iface, pv, cb, read_len);
149 if (!read_len)
150 read_len = &dummy;
152 if (stream->handle->size >= stream->position.LowPart)
153 len = min(stream->handle->size - stream->position.LowPart, cb);
154 else
155 len = 0;
157 buffer = GlobalLock(stream->handle->hglobal);
158 if (!buffer)
160 WARN("Failed to lock hglobal %p\n", stream->handle->hglobal);
161 *read_len = 0;
162 return S_OK;
165 memcpy(pv, buffer + stream->position.LowPart, len);
166 stream->position.LowPart += len;
168 *read_len = len;
170 GlobalUnlock(stream->handle->hglobal);
172 return S_OK;
175 static HRESULT WINAPI stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *written)
177 struct hglobal_stream *stream = impl_from_IStream(iface);
178 ULARGE_INTEGER size;
179 ULONG dummy = 0;
180 char *buffer;
182 TRACE("%p, %p, %ld, %p\n", iface, pv, cb, written);
184 if (!written)
185 written = &dummy;
187 if (!cb)
188 goto out;
190 *written = 0;
192 size.HighPart = 0;
193 size.LowPart = stream->position.LowPart + cb;
195 if (size.LowPart > stream->handle->size)
197 /* grow stream */
198 HRESULT hr = IStream_SetSize(iface, size);
199 if (FAILED(hr))
201 ERR("IStream_SetSize failed with error %#lx\n", hr);
202 return hr;
206 buffer = GlobalLock(stream->handle->hglobal);
207 if (!buffer)
209 WARN("write to invalid hglobal %p\n", stream->handle->hglobal);
210 return S_OK;
213 memcpy(buffer + stream->position.LowPart, pv, cb);
214 stream->position.LowPart += cb;
216 GlobalUnlock(stream->handle->hglobal);
218 out:
219 *written = cb;
221 return S_OK;
224 static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin,
225 ULARGE_INTEGER *pos)
227 struct hglobal_stream *stream = impl_from_IStream(iface);
228 ULARGE_INTEGER position = stream->position;
229 HRESULT hr = S_OK;
231 TRACE("%p, %s, %ld, %p\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, pos);
233 switch (origin)
235 case STREAM_SEEK_SET:
236 position.QuadPart = 0;
237 break;
238 case STREAM_SEEK_CUR:
239 break;
240 case STREAM_SEEK_END:
241 position.QuadPart = stream->handle->size;
242 break;
243 default:
244 hr = STG_E_SEEKERROR;
245 goto end;
248 position.HighPart = 0;
249 position.LowPart += move.QuadPart;
251 if (move.LowPart >= 0x80000000 && position.LowPart >= move.LowPart)
253 /* We tried to seek backwards and went past the start. */
254 hr = STG_E_SEEKERROR;
255 goto end;
258 stream->position = position;
260 end:
261 if (pos) *pos = stream->position;
263 return hr;
266 static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size)
268 struct hglobal_stream *stream = impl_from_IStream(iface);
269 HGLOBAL hglobal;
271 TRACE("%p, %s\n", iface, wine_dbgstr_longlong(size.QuadPart));
273 if (stream->handle->size == size.LowPart)
274 return S_OK;
276 hglobal = GlobalReAlloc(stream->handle->hglobal, size.LowPart, GMEM_MOVEABLE);
277 if (!hglobal)
278 return E_OUTOFMEMORY;
280 stream->handle->hglobal = hglobal;
281 stream->handle->size = size.LowPart;
283 return S_OK;
286 static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER cb,
287 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
289 ULARGE_INTEGER total_read, total_written;
290 HRESULT hr = S_OK;
291 BYTE buffer[128];
293 TRACE("%p, %p, %ld, %p, %p\n", iface, dest, cb.LowPart, read_len, written);
295 if (!dest)
296 return STG_E_INVALIDPOINTER;
298 total_read.QuadPart = 0;
299 total_written.QuadPart = 0;
301 while (cb.QuadPart > 0)
303 ULONG chunk_size = cb.QuadPart >= sizeof(buffer) ? sizeof(buffer) : cb.LowPart;
304 ULONG chunk_read, chunk_written;
306 hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
307 if (FAILED(hr))
308 break;
310 total_read.QuadPart += chunk_read;
312 if (chunk_read)
314 hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
315 if (FAILED(hr))
316 break;
318 total_written.QuadPart += chunk_written;
321 if (chunk_read != chunk_size)
322 cb.QuadPart = 0;
323 else
324 cb.QuadPart -= chunk_read;
327 if (read_len)
328 read_len->QuadPart = total_read.QuadPart;
329 if (written)
330 written->QuadPart = total_written.QuadPart;
332 return hr;
335 static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags)
337 return S_OK;
340 static HRESULT WINAPI stream_Revert(IStream *iface)
342 return S_OK;
345 static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
346 ULARGE_INTEGER len, DWORD lock_type)
348 return STG_E_INVALIDFUNCTION;
351 static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset,
352 ULARGE_INTEGER len, DWORD lock_type)
354 return S_OK;
357 static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD flags)
359 struct hglobal_stream *stream = impl_from_IStream(iface);
361 memset(pstatstg, 0, sizeof(STATSTG));
363 pstatstg->pwcsName = NULL;
364 pstatstg->type = STGTY_STREAM;
365 pstatstg->cbSize.QuadPart = stream->handle->size;
367 return S_OK;
370 static HRESULT WINAPI stream_Clone(IStream *iface, IStream **ppstm)
372 struct hglobal_stream *stream = impl_from_IStream(iface), *clone;
373 ULARGE_INTEGER dummy;
374 LARGE_INTEGER offset;
376 TRACE("%p, %p\n", iface, ppstm);
378 *ppstm = NULL;
380 clone = hglobalstream_construct();
381 if (!clone) return E_OUTOFMEMORY;
383 *ppstm = &clone->IStream_iface;
384 handle_addref(stream->handle);
385 clone->handle = stream->handle;
387 offset.QuadPart = (LONGLONG)stream->position.QuadPart;
388 IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
389 return S_OK;
392 static const IStreamVtbl hglobalstreamvtbl =
394 stream_QueryInterface,
395 stream_AddRef,
396 stream_Release,
397 stream_Read,
398 stream_Write,
399 stream_Seek,
400 stream_SetSize,
401 stream_CopyTo,
402 stream_Commit,
403 stream_Revert,
404 stream_LockRegion,
405 stream_UnlockRegion,
406 stream_Stat,
407 stream_Clone
410 /***********************************************************************
411 * CreateStreamOnHGlobal (combase.@)
413 HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL delete_on_release, IStream **stream)
415 struct hglobal_stream *object;
417 if (!stream)
418 return E_INVALIDARG;
420 object = hglobalstream_construct();
421 if (!object) return E_OUTOFMEMORY;
423 object->handle = handle_create(hGlobal, delete_on_release);
424 if (!object->handle)
426 free(object);
427 return E_OUTOFMEMORY;
430 *stream = &object->IStream_iface;
432 return S_OK;
435 /***********************************************************************
436 * GetHGlobalFromStream (combase.@)
438 HRESULT WINAPI GetHGlobalFromStream(IStream *stream, HGLOBAL *phglobal)
440 struct hglobal_stream *object;
442 if (!stream || !phglobal)
443 return E_INVALIDARG;
445 object = impl_from_IStream(stream);
447 if (object->IStream_iface.lpVtbl == &hglobalstreamvtbl)
448 *phglobal = object->handle->hglobal;
449 else
451 *phglobal = 0;
452 return E_INVALIDARG;
455 return S_OK;