Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/combase/hglobalstream.c
4393 views
1
/*
2
* HGLOBAL Stream implementation
3
*
4
* Copyright 1999 Francis Beaudet
5
* Copyright 2016 Dmitry Timoshkov
6
*
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.
11
*
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.
16
*
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
20
*/
21
22
#define COBJMACROS
23
#include "objbase.h"
24
25
#include "wine/debug.h"
26
27
WINE_DEFAULT_DEBUG_CHANNEL(storage);
28
29
struct handle_wrapper
30
{
31
LONG ref;
32
HGLOBAL hglobal;
33
ULONG size;
34
BOOL delete_on_release;
35
};
36
37
static void handle_addref(struct handle_wrapper *handle)
38
{
39
InterlockedIncrement(&handle->ref);
40
}
41
42
static void handle_release(struct handle_wrapper *handle)
43
{
44
ULONG ref = InterlockedDecrement(&handle->ref);
45
46
if (!ref)
47
{
48
if (handle->delete_on_release) GlobalFree(handle->hglobal);
49
free(handle);
50
}
51
}
52
53
static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release)
54
{
55
struct handle_wrapper *handle;
56
57
handle = malloc(sizeof(*handle));
58
if (!handle) return NULL;
59
60
/* allocate a handle if one is not supplied */
61
if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0);
62
if (!hglobal)
63
{
64
free(handle);
65
return NULL;
66
}
67
handle->ref = 1;
68
handle->hglobal = hglobal;
69
handle->size = GlobalSize(hglobal);
70
handle->delete_on_release = delete_on_release;
71
72
return handle;
73
}
74
75
struct hglobal_stream
76
{
77
IStream IStream_iface;
78
LONG ref;
79
80
struct handle_wrapper *handle;
81
ULARGE_INTEGER position;
82
};
83
84
static inline struct hglobal_stream *impl_from_IStream(IStream *iface)
85
{
86
return CONTAINING_RECORD(iface, struct hglobal_stream, IStream_iface);
87
}
88
89
static const IStreamVtbl hglobalstreamvtbl;
90
91
static struct hglobal_stream *hglobalstream_construct(void)
92
{
93
struct hglobal_stream *object = calloc(1, sizeof(*object));
94
95
if (object)
96
{
97
object->IStream_iface.lpVtbl = &hglobalstreamvtbl;
98
object->ref = 1;
99
}
100
return object;
101
}
102
103
static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj)
104
{
105
if (!obj)
106
return E_INVALIDARG;
107
108
if (IsEqualIID(&IID_IUnknown, riid) ||
109
IsEqualIID(&IID_ISequentialStream, riid) ||
110
IsEqualIID(&IID_IStream, riid))
111
{
112
*obj = iface;
113
IStream_AddRef(iface);
114
return S_OK;
115
}
116
117
*obj = NULL;
118
return E_NOINTERFACE;
119
}
120
121
static ULONG WINAPI stream_AddRef(IStream *iface)
122
{
123
struct hglobal_stream *stream = impl_from_IStream(iface);
124
return InterlockedIncrement(&stream->ref);
125
}
126
127
static ULONG WINAPI stream_Release(IStream *iface)
128
{
129
struct hglobal_stream *stream = impl_from_IStream(iface);
130
ULONG ref = InterlockedDecrement(&stream->ref);
131
132
if (!ref)
133
{
134
handle_release(stream->handle);
135
free(stream);
136
}
137
138
return ref;
139
}
140
141
static HRESULT WINAPI stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *read_len)
142
{
143
struct hglobal_stream *stream = impl_from_IStream(iface);
144
ULONG dummy, len;
145
char *buffer;
146
147
TRACE("%p, %p, %ld, %p\n", iface, pv, cb, read_len);
148
149
if (!read_len)
150
read_len = &dummy;
151
152
if (stream->handle->size >= stream->position.LowPart)
153
len = min(stream->handle->size - stream->position.LowPart, cb);
154
else
155
len = 0;
156
157
buffer = GlobalLock(stream->handle->hglobal);
158
if (!buffer)
159
{
160
WARN("Failed to lock hglobal %p\n", stream->handle->hglobal);
161
*read_len = 0;
162
return S_OK;
163
}
164
165
memcpy(pv, buffer + stream->position.LowPart, len);
166
stream->position.LowPart += len;
167
168
*read_len = len;
169
170
GlobalUnlock(stream->handle->hglobal);
171
172
return S_OK;
173
}
174
175
static HRESULT WINAPI stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *written)
176
{
177
struct hglobal_stream *stream = impl_from_IStream(iface);
178
ULARGE_INTEGER size;
179
ULONG dummy = 0;
180
char *buffer;
181
182
TRACE("%p, %p, %ld, %p\n", iface, pv, cb, written);
183
184
if (!written)
185
written = &dummy;
186
187
if (!cb)
188
goto out;
189
190
*written = 0;
191
192
size.HighPart = 0;
193
size.LowPart = stream->position.LowPart + cb;
194
195
if (size.LowPart > stream->handle->size)
196
{
197
/* grow stream */
198
HRESULT hr = IStream_SetSize(iface, size);
199
if (FAILED(hr))
200
{
201
ERR("IStream_SetSize failed with error %#lx\n", hr);
202
return hr;
203
}
204
}
205
206
buffer = GlobalLock(stream->handle->hglobal);
207
if (!buffer)
208
{
209
WARN("write to invalid hglobal %p\n", stream->handle->hglobal);
210
return S_OK;
211
}
212
213
memcpy(buffer + stream->position.LowPart, pv, cb);
214
stream->position.LowPart += cb;
215
216
GlobalUnlock(stream->handle->hglobal);
217
218
out:
219
*written = cb;
220
221
return S_OK;
222
}
223
224
static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin,
225
ULARGE_INTEGER *pos)
226
{
227
struct hglobal_stream *stream = impl_from_IStream(iface);
228
ULARGE_INTEGER position = stream->position;
229
HRESULT hr = S_OK;
230
231
TRACE("%p, %s, %ld, %p\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, pos);
232
233
switch (origin)
234
{
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;
246
}
247
248
position.HighPart = 0;
249
position.LowPart += move.QuadPart;
250
251
if (move.LowPart >= 0x80000000 && position.LowPart >= move.LowPart)
252
{
253
/* We tried to seek backwards and went past the start. */
254
hr = STG_E_SEEKERROR;
255
goto end;
256
}
257
258
stream->position = position;
259
260
end:
261
if (pos) *pos = stream->position;
262
263
return hr;
264
}
265
266
static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size)
267
{
268
struct hglobal_stream *stream = impl_from_IStream(iface);
269
HGLOBAL hglobal;
270
271
TRACE("%p, %s\n", iface, wine_dbgstr_longlong(size.QuadPart));
272
273
if (stream->handle->size == size.LowPart)
274
return S_OK;
275
276
hglobal = GlobalReAlloc(stream->handle->hglobal, size.LowPart, GMEM_MOVEABLE);
277
if (!hglobal)
278
return E_OUTOFMEMORY;
279
280
stream->handle->hglobal = hglobal;
281
stream->handle->size = size.LowPart;
282
283
return S_OK;
284
}
285
286
static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER cb,
287
ULARGE_INTEGER *read_len, ULARGE_INTEGER *written)
288
{
289
ULARGE_INTEGER total_read, total_written;
290
HRESULT hr = S_OK;
291
BYTE buffer[128];
292
293
TRACE("%p, %p, %ld, %p, %p\n", iface, dest, cb.LowPart, read_len, written);
294
295
if (!dest)
296
return STG_E_INVALIDPOINTER;
297
298
total_read.QuadPart = 0;
299
total_written.QuadPart = 0;
300
301
while (cb.QuadPart > 0)
302
{
303
ULONG chunk_size = cb.QuadPart >= sizeof(buffer) ? sizeof(buffer) : cb.LowPart;
304
ULONG chunk_read, chunk_written;
305
306
hr = IStream_Read(iface, buffer, chunk_size, &chunk_read);
307
if (FAILED(hr))
308
break;
309
310
total_read.QuadPart += chunk_read;
311
312
if (chunk_read)
313
{
314
hr = IStream_Write(dest, buffer, chunk_read, &chunk_written);
315
if (FAILED(hr))
316
break;
317
318
total_written.QuadPart += chunk_written;
319
}
320
321
if (chunk_read != chunk_size)
322
cb.QuadPart = 0;
323
else
324
cb.QuadPart -= chunk_read;
325
}
326
327
if (read_len)
328
read_len->QuadPart = total_read.QuadPart;
329
if (written)
330
written->QuadPart = total_written.QuadPart;
331
332
return hr;
333
}
334
335
static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags)
336
{
337
return S_OK;
338
}
339
340
static HRESULT WINAPI stream_Revert(IStream *iface)
341
{
342
return S_OK;
343
}
344
345
static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
346
ULARGE_INTEGER len, DWORD lock_type)
347
{
348
return STG_E_INVALIDFUNCTION;
349
}
350
351
static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset,
352
ULARGE_INTEGER len, DWORD lock_type)
353
{
354
return S_OK;
355
}
356
357
static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD flags)
358
{
359
struct hglobal_stream *stream = impl_from_IStream(iface);
360
361
memset(pstatstg, 0, sizeof(STATSTG));
362
363
pstatstg->pwcsName = NULL;
364
pstatstg->type = STGTY_STREAM;
365
pstatstg->cbSize.QuadPart = stream->handle->size;
366
367
return S_OK;
368
}
369
370
static HRESULT WINAPI stream_Clone(IStream *iface, IStream **ppstm)
371
{
372
struct hglobal_stream *stream = impl_from_IStream(iface), *clone;
373
ULARGE_INTEGER dummy;
374
LARGE_INTEGER offset;
375
376
TRACE("%p, %p\n", iface, ppstm);
377
378
*ppstm = NULL;
379
380
clone = hglobalstream_construct();
381
if (!clone) return E_OUTOFMEMORY;
382
383
*ppstm = &clone->IStream_iface;
384
handle_addref(stream->handle);
385
clone->handle = stream->handle;
386
387
offset.QuadPart = (LONGLONG)stream->position.QuadPart;
388
IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy);
389
return S_OK;
390
}
391
392
static const IStreamVtbl hglobalstreamvtbl =
393
{
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
408
};
409
410
/***********************************************************************
411
* CreateStreamOnHGlobal (combase.@)
412
*/
413
HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL delete_on_release, IStream **stream)
414
{
415
struct hglobal_stream *object;
416
417
if (!stream)
418
return E_INVALIDARG;
419
420
object = hglobalstream_construct();
421
if (!object) return E_OUTOFMEMORY;
422
423
object->handle = handle_create(hGlobal, delete_on_release);
424
if (!object->handle)
425
{
426
free(object);
427
return E_OUTOFMEMORY;
428
}
429
430
*stream = &object->IStream_iface;
431
432
return S_OK;
433
}
434
435
/***********************************************************************
436
* GetHGlobalFromStream (combase.@)
437
*/
438
HRESULT WINAPI GetHGlobalFromStream(IStream *stream, HGLOBAL *phglobal)
439
{
440
struct hglobal_stream *object;
441
442
if (!stream || !phglobal)
443
return E_INVALIDARG;
444
445
object = impl_from_IStream(stream);
446
447
if (object->IStream_iface.lpVtbl == &hglobalstreamvtbl)
448
*phglobal = object->handle->hglobal;
449
else
450
{
451
*phglobal = 0;
452
return E_INVALIDARG;
453
}
454
455
return S_OK;
456
}
457
458