Add de-interleaving for GIF images.
[wine] / dlls / ole32 / memlockbytes.c
1 /******************************************************************************
2  *
3  * Global memory implementation of ILockBytes.
4  *
5  * Copyright 1999 Thuy Nguyen
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wine/winbase16.h"
34 #include "objbase.h"
35 #include "ole2.h"
36 #include "winerror.h"
37
38 #include "ifs.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43
44 /******************************************************************************
45  * HGLOBALLockBytesImpl definition.
46  *
47  * This class imlements the ILockBytes inteface and represents a byte array
48  * object supported by an HGLOBAL pointer.
49  */
50 struct HGLOBALLockBytesImpl
51 {
52   /*
53    * Needs to be the first item in the stuct
54    * since we want to cast this in an ILockBytes pointer
55    */
56   ILockBytesVtbl *lpVtbl;
57
58   /*
59    * Reference count
60    */
61   ULONG        ref;
62
63   /*
64    * Support for the LockBytes object
65    */
66   HGLOBAL supportHandle;
67
68   /*
69    * This flag is TRUE if the HGLOBAL is destroyed when the object
70    * is finally released.
71    */
72   BOOL    deleteOnRelease;
73
74   /*
75    * Helper variable that contains the size of the byte array
76    */
77   ULARGE_INTEGER     byteArraySize;
78 };
79
80 typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
81
82 /*
83  * Method definition for the HGLOBALLockBytesImpl class.
84  */
85 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(
86     HGLOBAL  hGlobal,
87     BOOL     fDeleteOnRelease);
88
89 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This);
90
91 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
92     ILockBytes*   iface,
93     REFIID        riid,        /* [in] */
94     void**        ppvObject);  /* [iid_is][out] */
95
96 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(
97     ILockBytes*   iface);
98
99 ULONG WINAPI HGLOBALLockBytesImpl_Release(
100     ILockBytes*   iface);
101
102 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
103     ILockBytes*    iface,
104     ULARGE_INTEGER ulOffset,  /* [in] */
105     void*          pv,        /* [length_is][size_is][out] */
106     ULONG          cb,        /* [in] */
107     ULONG*         pcbRead);  /* [out] */
108
109 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
110     ILockBytes*    iface,
111     ULARGE_INTEGER ulOffset,    /* [in] */
112     const void*    pv,          /* [size_is][in] */
113     ULONG          cb,          /* [in] */
114     ULONG*         pcbWritten); /* [out] */
115
116 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(
117     ILockBytes*     iface);
118
119 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
120     ILockBytes*     iface,
121     ULARGE_INTEGER  libNewSize);  /* [in] */
122
123 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
124     ILockBytes*    iface,
125     ULARGE_INTEGER libOffset,   /* [in] */
126     ULARGE_INTEGER cb,          /* [in] */
127     DWORD          dwLockType); /* [in] */
128
129 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
130     ILockBytes*    iface,
131     ULARGE_INTEGER libOffset,   /* [in] */
132     ULARGE_INTEGER cb,          /* [in] */
133     DWORD          dwLockType); /* [in] */
134
135 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
136     ILockBytes*    iface,
137     STATSTG*       pstatstg,     /* [out] */
138     DWORD          grfStatFlag); /* [in]  */
139
140 /*
141  * Virtual function table for the HGLOBALLockBytesImpl class.
142  */
143 static ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
144 {
145     HGLOBALLockBytesImpl_QueryInterface,
146     HGLOBALLockBytesImpl_AddRef,
147     HGLOBALLockBytesImpl_Release,
148     HGLOBALLockBytesImpl_ReadAt,
149     HGLOBALLockBytesImpl_WriteAt,
150     HGLOBALLockBytesImpl_Flush,
151     HGLOBALLockBytesImpl_SetSize,
152     HGLOBALLockBytesImpl_LockRegion,
153     HGLOBALLockBytesImpl_UnlockRegion,
154     HGLOBALLockBytesImpl_Stat,
155 };
156
157 /******************************************************************************
158  *           CreateILockBytesOnHGlobal     [OLE32.@]
159  */
160 HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL      hGlobal,
161                                          BOOL         fDeleteOnRelease,
162                                          LPLOCKBYTES* ppLkbyt)
163 {
164   HGLOBALLockBytesImpl* newLockBytes;
165
166   newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease);
167
168   if (newLockBytes != NULL)
169   {
170     return IUnknown_QueryInterface((IUnknown*)newLockBytes,
171                                    &IID_ILockBytes,
172                                    (void**)ppLkbyt);
173   }
174
175   return E_OUTOFMEMORY;
176 }
177
178 /******************************************************************************
179  *           GetHGlobalFromILockBytes     [OLE32.@]
180  */
181 HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal)
182 {
183   HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt;
184   STATSTG stbuf;
185   HRESULT hres;
186   ULARGE_INTEGER start;
187   ULONG xread;
188
189   *phglobal = 0;
190   if (pMemLockBytes->lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
191     *phglobal = pMemLockBytes->supportHandle;
192     if (*phglobal == 0)
193       return E_INVALIDARG;
194     return S_OK;
195   }
196   /* It is not our lockbytes implementation, so use a more generic way */
197   hres = ILockBytes_Stat(plkbyt,&stbuf,0);
198   if (hres != S_OK) {
199      ERR("Cannot ILockBytes_Stat, %lx\n",hres);
200      return hres;
201   }
202   FIXME("cbSize is %ld\n",stbuf.cbSize.u.LowPart);
203   *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart);
204   if (!*phglobal)
205     return E_INVALIDARG;
206   memset(&start,0,sizeof(start));
207   hres = ILockBytes_ReadAt(plkbyt, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread);
208   GlobalUnlock(*phglobal);
209   if (hres != S_OK) {
210     FIXME("%p->ReadAt failed with %lx\n",plkbyt,hres);
211     return hres;
212   }
213   if (stbuf.cbSize.u.LowPart != xread) {
214     FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.u.LowPart, xread);
215   }
216   return S_OK;
217 }
218
219 /******************************************************************************
220  *
221  * HGLOBALLockBytesImpl implementation
222  *
223  */
224
225 /******************************************************************************
226  * This is the constructor for the HGLOBALLockBytesImpl class.
227  *
228  * Params:
229  *    hGlobal          - Handle that will support the stream. can be NULL.
230  *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
231  *                       when the IStream object is destroyed.
232  */
233 HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal,
234                                                      BOOL    fDeleteOnRelease)
235 {
236   HGLOBALLockBytesImpl* newLockBytes;
237   newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
238
239   if (newLockBytes!=0)
240   {
241     /*
242      * Set up the virtual function table and reference count.
243      */
244     newLockBytes->lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
245     newLockBytes->ref    = 0;
246
247     /*
248      * Initialize the support.
249      */
250     newLockBytes->supportHandle = hGlobal;
251     newLockBytes->deleteOnRelease = fDeleteOnRelease;
252
253     /*
254      * This method will allocate a handle if one is not supplied.
255      */
256     if (newLockBytes->supportHandle == 0)
257     {
258       newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE |
259                                                 GMEM_NODISCARD,
260                                                 0);
261     }
262
263     /*
264      * Initialize the size of the array to the size of the handle.
265      */
266     newLockBytes->byteArraySize.u.HighPart = 0;
267     newLockBytes->byteArraySize.u.LowPart  = GlobalSize(
268                                               newLockBytes->supportHandle);
269   }
270
271   return newLockBytes;
272 }
273
274 /******************************************************************************
275  * This is the destructor of the HGLOBALStreamImpl class.
276  *
277  * This method will clean-up all the resources used-up by the given
278  * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be
279  * freed and will not be valid anymore.
280  */
281 void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This)
282 {
283   /*
284    * Release the HGlobal if the constructor asked for that.
285    */
286   if (This->deleteOnRelease)
287   {
288     GlobalFree(This->supportHandle);
289     This->supportHandle = 0;
290   }
291
292   /*
293    * Finally, free the memory used-up by the class.
294    */
295   HeapFree(GetProcessHeap(), 0, This);
296 }
297
298 /******************************************************************************
299  * This implements the IUnknown method QueryInterface for this
300  * class
301  */
302 HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
303       ILockBytes*  iface,
304       REFIID       riid,        /* [in] */
305       void**       ppvObject)   /* [iid_is][out] */
306 {
307   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
308
309   /*
310    * Perform a sanity check on the parameters.
311    */
312   if (ppvObject==0)
313     return E_INVALIDARG;
314
315   /*
316    * Initialize the return parameter.
317    */
318   *ppvObject = 0;
319
320   /*
321    * Compare the riid with the interface IDs implemented by this object.
322    */
323   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
324   {
325     *ppvObject = (ILockBytes*)This;
326   }
327   else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
328   {
329     *ppvObject = (ILockBytes*)This;
330   }
331
332   /*
333    * Check that we obtained an interface.
334    */
335   if ((*ppvObject)==0)
336     return E_NOINTERFACE;
337
338   /*
339    * Query Interface always increases the reference count by one when it is
340    * successful
341    */
342   HGLOBALLockBytesImpl_AddRef(iface);
343
344   return S_OK;
345 }
346
347 /******************************************************************************
348  * This implements the IUnknown method AddRef for this
349  * class
350  */
351 ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
352 {
353   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
354
355   This->ref++;
356
357   return This->ref;
358 }
359
360 /******************************************************************************
361  * This implements the IUnknown method Release for this
362  * class
363  */
364 ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
365 {
366   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
367
368   ULONG newRef;
369
370   This->ref--;
371
372   newRef = This->ref;
373
374   /*
375    * If the reference count goes down to 0, perform suicide.
376    */
377   if (newRef==0)
378   {
379     HGLOBALLockBytesImpl_Destroy(This);
380   }
381
382   return newRef;
383 }
384
385 /******************************************************************************
386  * This method is part of the ILockBytes interface.
387  *
388  * It reads a block of information from the byte array at the specified
389  * offset.
390  *
391  * See the documentation of ILockBytes for more info.
392  */
393 HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
394       ILockBytes*    iface,
395       ULARGE_INTEGER ulOffset,  /* [in] */
396       void*          pv,        /* [length_is][size_is][out] */
397       ULONG          cb,        /* [in] */
398       ULONG*         pcbRead)   /* [out] */
399 {
400   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
401
402   void* supportBuffer;
403   ULONG bytesReadBuffer = 0;
404   ULONG bytesToReadFromBuffer;
405
406   /*
407    * If the caller is not interested in the number of bytes read,
408    * we use another buffer to avoid "if" statements in the code.
409    */
410   if (pcbRead == 0)
411     pcbRead = &bytesReadBuffer;
412
413   /*
414    * Make sure the offset is valid.
415    */
416   if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart)
417     return E_FAIL;
418
419   /*
420    * Using the known size of the array, calculate the number of bytes
421    * to read.
422    */
423   bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart -
424                               ulOffset.u.LowPart, cb);
425
426   /*
427    * Lock the buffer in position and copy the data.
428    */
429   supportBuffer = GlobalLock(This->supportHandle);
430
431   memcpy(pv,
432          (char *) supportBuffer + ulOffset.u.LowPart,
433          bytesToReadFromBuffer);
434
435   /*
436    * Return the number of bytes read.
437    */
438   *pcbRead = bytesToReadFromBuffer;
439
440   /*
441    * Cleanup
442    */
443   GlobalUnlock(This->supportHandle);
444
445   /*
446    * The function returns S_OK if the specified number of bytes were read
447    * or the end of the array was reached.
448    * It returns STG_E_READFAULT if the number of bytes to read does not equal
449    * the number of bytes actually read.
450    */
451   if(*pcbRead == cb)
452     return S_OK;
453
454   return STG_E_READFAULT;
455 }
456
457 /******************************************************************************
458  * This method is part of the ILockBytes interface.
459  *
460  * It writes the specified bytes at the specified offset.
461  * position. If the array is too small, it will be resized.
462  *
463  * See the documentation of ILockBytes for more info.
464  */
465 HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
466       ILockBytes*    iface,
467       ULARGE_INTEGER ulOffset,    /* [in] */
468       const void*    pv,          /* [size_is][in] */
469       ULONG          cb,          /* [in] */
470       ULONG*         pcbWritten)  /* [out] */
471 {
472   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
473
474   void*          supportBuffer;
475   ULARGE_INTEGER newSize;
476   ULONG          bytesWritten = 0;
477
478   /*
479    * If the caller is not interested in the number of bytes written,
480    * we use another buffer to avoid "if" statements in the code.
481    */
482   if (pcbWritten == 0)
483     pcbWritten = &bytesWritten;
484
485   if (cb == 0)
486   {
487     return S_OK;
488   }
489   else
490   {
491     newSize.u.HighPart = 0;
492     newSize.u.LowPart = ulOffset.u.LowPart + cb;
493   }
494
495   /*
496    * Verify if we need to grow the stream
497    */
498   if (newSize.u.LowPart > This->byteArraySize.u.LowPart)
499   {
500     /* grow stream */
501     if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
502       return STG_E_MEDIUMFULL;
503   }
504
505   /*
506    * Lock the buffer in position and copy the data.
507    */
508   supportBuffer = GlobalLock(This->supportHandle);
509
510   memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb);
511
512   /*
513    * Return the number of bytes written.
514    */
515   *pcbWritten = cb;
516
517   /*
518    * Cleanup
519    */
520   GlobalUnlock(This->supportHandle);
521
522   return S_OK;
523 }
524
525 /******************************************************************************
526  * This method is part of the ILockBytes interface.
527  *
528  * See the documentation of ILockBytes for more info.
529  */
530 HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
531 {
532   return S_OK;
533 }
534
535 /******************************************************************************
536  * This method is part of the ILockBytes interface.
537  *
538  * It will change the size of the byte array.
539  *
540  * See the documentation of ILockBytes for more info.
541  */
542 HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
543       ILockBytes*     iface,
544       ULARGE_INTEGER  libNewSize)   /* [in] */
545 {
546   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
547   HGLOBAL supportHandle;
548
549   /*
550    * As documented.
551    */
552   if (libNewSize.u.HighPart != 0)
553     return STG_E_INVALIDFUNCTION;
554
555   if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart)
556     return S_OK;
557
558   /*
559    * Re allocate the HGlobal to fit the new size of the stream.
560    */
561   supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0);
562
563   if (supportHandle == 0)
564     return STG_E_MEDIUMFULL;
565
566   This->supportHandle = supportHandle;
567   This->byteArraySize.u.LowPart = libNewSize.u.LowPart;
568
569   return S_OK;
570 }
571
572 /******************************************************************************
573  * This method is part of the ILockBytes interface.
574  *
575  * The global memory implementation of ILockBytes does not support locking.
576  *
577  * See the documentation of ILockBytes for more info.
578  */
579 HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
580       ILockBytes*    iface,
581       ULARGE_INTEGER libOffset,   /* [in] */
582       ULARGE_INTEGER cb,          /* [in] */
583       DWORD          dwLockType)  /* [in] */
584 {
585   return STG_E_INVALIDFUNCTION;
586 }
587
588 /******************************************************************************
589  * This method is part of the ILockBytes interface.
590  *
591  * The global memory implementation of ILockBytes does not support locking.
592  *
593  * See the documentation of ILockBytes for more info.
594  */
595 HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
596       ILockBytes*    iface,
597       ULARGE_INTEGER libOffset,   /* [in] */
598       ULARGE_INTEGER cb,          /* [in] */
599       DWORD          dwLockType)  /* [in] */
600 {
601   return STG_E_INVALIDFUNCTION;
602 }
603
604 /******************************************************************************
605  * This method is part of the ILockBytes interface.
606  *
607  * This method returns information about the current
608  * byte array object.
609  *
610  * See the documentation of ILockBytes for more info.
611  */
612 HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
613       ILockBytes*  iface,
614       STATSTG*     pstatstg,     /* [out] */
615       DWORD        grfStatFlag)  /* [in] */
616 {
617   HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
618
619   memset(pstatstg, 0, sizeof(STATSTG));
620
621   pstatstg->pwcsName = NULL;
622   pstatstg->type     = STGTY_LOCKBYTES;
623   pstatstg->cbSize   = This->byteArraySize;
624
625   return S_OK;
626 }