d3dcompiler: Allow D3DCompile2() to succeed with null output shader blob pointer.
[wine.git] / dlls / combase / hglobalstream.c
blob04eeeab777900b377165f7ed133bf02b0294b6db
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 #define NONAMELESSUNION
25 #include "objbase.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(storage);
31 struct handle_wrapper
33 LONG ref;
34 HGLOBAL hglobal;
35 ULONG size;
36 BOOL delete_on_release;
39 static void handle_addref(struct handle_wrapper *handle)
41 InterlockedIncrement(&handle->ref);
44 static void handle_release(struct handle_wrapper *handle)
46 ULONG ref = InterlockedDecrement(&handle->ref);
48 if (!ref)
50 if (handle->delete_on_release) GlobalFree(handle->hglobal);
51 free(handle);
55 static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
57 struct handle_wrapper *handle;
59 handle = malloc(sizeof(*handle));
60 if (!handle) return NULL;
62 /* allocate a handle if one is not supplied */
63 if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0);
64 if (!hglobal)
66 free(handle);
67 return NULL;
69 handle->ref = 1;
70 handle->hglobal = hglobal;
71 handle->size = GlobalSize(hglobal);
72 handle->delete_on_release = delete_on_release;
74 return handle;
77 struct hglobal_stream
79 IStream IStream_iface;
80 LONG ref;
82 struct handle_wrapper *handle;
83 ULARGE_INTEGER position;
86 static inline struct hglobal_stream *impl_from_IStream(IStream *iface)
88 return CONTAINING_RECORD(iface, struct hglobal_stream, IStream_iface);
91 static const IStreamVtbl hglobalstreamvtbl;
93 static struct hglobal_stream *hglobalstream_construct(void)
95 struct hglobal_stream *object = calloc(1, sizeof(*object));
97 if (object)
99 object->IStream_iface.lpVtbl = &hglobalstreamvtbl;
100 object->ref = 1;
102 return object;
105 static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj)
107 if (!obj)
108 return E_INVALIDARG;
110 if (IsEqualIID(&IID_IUnknown, riid) ||
111 IsEqualIID(&IID_ISequentialStream, riid) ||
112 IsEqualIID(&IID_IStream, riid))
114 *obj = iface;
115 IStream_AddRef(iface);
116 return S_OK;
119 *obj = NULL;
120 return E_NOINTERFACE;
123 static ULONG WINAPI stream_AddRef(IStream *iface)
125 struct hglobal_stream *stream = impl_from_IStream(iface);
126 return InterlockedIncrement(&stream->ref);
129 static ULONG WINAPI stream_Release(IStream *iface)
131 struct hglobal_stream *stream = impl_from_IStream(iface);
132 ULONG ref = InterlockedDecrement(&stream->ref);
134 if (!ref)
136 handle_release(stream->handle);
137 free(stream);
140 return ref;
143 static HRESULT WINAPI stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *read_len)
145 struct hglobal_stream *stream = impl_from_IStream(iface);
146 ULONG dummy, len;
147 char *buffer;
149 TRACE("%p, %p, %ld, %p\n", iface, pv, cb, read_len);
151 if (!read_len)
152 read_len = &dummy;
154 len = min(stream->handle->size - stream->position.u.LowPart, cb);
156 buffer = GlobalLock(stream->handle->hglobal);
157 if (!buffer)
159 WARN("Failed to lock hglobal %p\n", stream->handle->hglobal);
160 *read_len = 0;
161 return S_OK;
164 memcpy(pv, buffer + stream->position.u.LowPart, len);
165 stream->position.u.LowPart += len;
167 *read_len = len;
169 GlobalUnlock(stream->handle->hglobal);
171 return S_OK;
174 static HRESULT WINAPI stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *written)
176 struct hglobal_stream *stream = impl_from_IStream(iface);
177 ULARGE_INTEGER size;
178 ULONG dummy = 0;
179 char *buffer;
181 TRACE("%p, %p, %ld, %p\n", iface, pv, cb, written);
183 if (!written)
184 written = &dummy;
186 if (!cb)
187 goto out;
189 *written = 0;
191 size.u.HighPart = 0;
192 size.u.LowPart = stream->position.u.LowPart + cb;
194 if (size.u.LowPart > stream->handle->size)
196 /* grow stream */
197 HRESULT hr = IStream_SetSize(iface, size);
198 if (FAILED(hr))
200 ERR("IStream_SetSize failed with error %#lx\n", hr);
201 return hr;
205 buffer = GlobalLock(stream->handle->hglobal);
206 if (!buffer)
208 WARN("write to invalid hglobal %p\n", stream->handle->hglobal);
209 return S_OK;
212 memcpy(buffer + stream->position.u.LowPart, pv, cb);
213 stream->position.u.LowPart += cb;
215 GlobalUnlock(stream->handle->hglobal);
217 out:
218 *written = cb;
220 return S_OK;
223 static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin,
224 ULARGE_INTEGER *pos)
226 struct hglobal_stream *stream = impl_from_IStream(iface);
227 ULARGE_INTEGER position = stream->position;
228 HRESULT hr = S_OK;
230 TRACE("%p, %s, %ld, %p\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, pos);
232 switch (origin)
234 case STREAM_SEEK_SET:
235 position.QuadPart = 0;
236 break;
237 case STREAM_SEEK_CUR:
238 break;
239 case STREAM_SEEK_END:
240 position.QuadPart = stream->handle->size;
241 break;
242 default:
243 hr = STG_E_SEEKERROR;
244 goto end;
247 position.u.HighPart = 0;
248 position.u.LowPart += move.QuadPart;
250 if (move.u.LowPart >= 0x80000000 && position.u.LowPart >= move.u.LowPart)
252 /* We tried to seek backwards and went past the start. */
253 hr = STG_E_SEEKERROR;
254 goto end;
257 stream->position = position;
259 end:
260 if (pos) *pos = stream->position;
262 return hr;
265 static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size)
267 struct hglobal_stream *stream = impl_from_IStream(iface);
268 HGLOBAL hglobal;
270 TRACE("%p, %s\n", iface, wine_dbgstr_longlong(size.QuadPart));
272 if (stream->handle->size == size.u.LowPart)
273 return S_OK;
275 hglobal = GlobalReAlloc(stream->handle->hglobal, size.u.LowPart, GMEM_MOVEABLE);
276 if (!hglobal)
277 return E_OUTOFMEMORY;
279 stream->handle->hglobal = hglobal;
280 stream->handle->size = size.u.LowPart;
282 return S_OK;
285 static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER cb,
286 ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
288 ULARGE_INTEGER total_read, total_written;
289 HRESULT hr = S_OK;
290 BYTE buffer[128];
292 TRACE("%p, %p, %ld, %p, %p\n", iface, dest, cb.u.LowPart, read_len, written);
294 if (!dest)
295 return STG_E_INVALIDPOINTER;
297 total_read.QuadPart = 0;
298 total_written.QuadPart = 0;
300 while (cb.QuadPart > 0)
302 ULONG chunk_size = cb.QuadPart >= sizeof(buffer) ? sizeof(buffer) : cb.u.LowPart;
303 ULONG chunk_read, chunk_written;
305 hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
306 if (FAILED(hr))
307 break;
309 total_read.QuadPart += chunk_read;
311 if (chunk_read)
313 hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
314 if (FAILED(hr))
315 break;
317 total_written.QuadPart += chunk_written;
320 if (chunk_read != chunk_size)
321 cb.QuadPart = 0;
322 else
323 cb.QuadPart -= chunk_read;
326 if (read_len)
327 read_len->QuadPart = total_read.QuadPart;
328 if (written)
329 written->QuadPart = total_written.QuadPart;
331 return hr;
334 static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags)
336 return S_OK;
339 static HRESULT WINAPI stream_Revert(IStream *iface)
341 return S_OK;
344 static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
345 ULARGE_INTEGER len, DWORD lock_type)
347 return STG_E_INVALIDFUNCTION;
350 static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset,
351 ULARGE_INTEGER len, DWORD lock_type)
353 return S_OK;
356 static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD flags)
358 struct hglobal_stream *stream = impl_from_IStream(iface);
360 memset(pstatstg, 0, sizeof(STATSTG));
362 pstatstg->pwcsName = NULL;
363 pstatstg->type = STGTY_STREAM;
364 pstatstg->cbSize.QuadPart = stream->handle->size;
366 return S_OK;
369 static HRESULT WINAPI stream_Clone(IStream *iface, IStream **ppstm)
371 struct hglobal_stream *stream = impl_from_IStream(iface), *clone;
372 ULARGE_INTEGER dummy;
373 LARGE_INTEGER offset;
375 TRACE("%p, %p\n", iface, ppstm);
377 *ppstm = NULL;
379 clone = hglobalstream_construct();
380 if (!clone) return E_OUTOFMEMORY;
382 *ppstm = &clone->IStream_iface;
383 handle_addref(stream->handle);
384 clone->handle = stream->handle;
386 offset.QuadPart = (LONGLONG)stream->position.QuadPart;
387 IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
388 return S_OK;
391 static const IStreamVtbl hglobalstreamvtbl =
393 stream_QueryInterface,
394 stream_AddRef,
395 stream_Release,
396 stream_Read,
397 stream_Write,
398 stream_Seek,
399 stream_SetSize,
400 stream_CopyTo,
401 stream_Commit,
402 stream_Revert,
403 stream_LockRegion,
404 stream_UnlockRegion,
405 stream_Stat,
406 stream_Clone
409 /***********************************************************************
410 * CreateStreamOnHGlobal (combase.@)
412 HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL delete_on_release, IStream **stream)
414 struct hglobal_stream *object;
416 if (!stream)
417 return E_INVALIDARG;
419 object = hglobalstream_construct();
420 if (!object) return E_OUTOFMEMORY;
422 object->handle = handle_create(hGlobal, delete_on_release);
423 if (!object->handle)
425 free(object);
426 return E_OUTOFMEMORY;
429 *stream = &object->IStream_iface;
431 return S_OK;
434 /***********************************************************************
435 * GetHGlobalFromStream (combase.@)
437 HRESULT WINAPI GetHGlobalFromStream(IStream *stream, HGLOBAL *phglobal)
439 struct hglobal_stream *object;
441 if (!stream || !phglobal)
442 return E_INVALIDARG;
444 object = impl_from_IStream(stream);
446 if (object->IStream_iface.lpVtbl == &hglobalstreamvtbl)
447 *phglobal = object->handle->hglobal;
448 else
450 *phglobal = 0;
451 return E_INVALIDARG;
454 return S_OK;