msvfw32: Avoid possible dereference of NULL pointer (Coverity).
[wine] / dlls / msvfw32 / drawdib.c
1 /*
2  * Copyright 2000 Bradley Baetz
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * FIXME: Some flags are ignored
19  *
20  * Handle palettes
21  */
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "vfw.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvideo);
36
37 typedef struct tagWINE_HDD {
38     HDC                 hdc;
39     INT                 dxDst;
40     INT                 dyDst;
41     LPBITMAPINFOHEADER  lpbi;
42     INT                 dxSrc;
43     INT                 dySrc;
44     HPALETTE            hpal;           /* Palette to use for the DIB */
45     BOOL                begun;          /* DrawDibBegin has been called */
46     LPBITMAPINFOHEADER  lpbiOut;        /* Output format */
47     HIC                 hic;            /* HIC for decompression */
48     HDC                 hMemDC;         /* DC for buffering */
49     HBITMAP             hOldDib;        /* Original Dib */
50     HBITMAP             hDib;           /* DibSection */
51     LPVOID              lpvbits;        /* Buffer for holding decompressed dib */
52     HDRAWDIB            hSelf;
53     struct tagWINE_HDD* next;
54 } WINE_HDD;
55
56 static int num_colours(const BITMAPINFOHEADER *lpbi)
57 {
58         if(lpbi->biClrUsed)
59                 return lpbi->biClrUsed;
60         if(lpbi->biBitCount<=8)
61                 return 1<<lpbi->biBitCount;
62         return 0;
63 }
64
65 static WINE_HDD*        HDD_FirstHdd /* = NULL */;
66
67 static WINE_HDD*       MSVIDEO_GetHddPtr(HDRAWDIB hd)
68 {
69     WINE_HDD*   hdd;
70
71     for (hdd = HDD_FirstHdd; hdd != NULL && hdd->hSelf != hd; hdd = hdd->next);
72     return hdd;
73 }
74
75 static DWORD HDD_HandleRef = 1;
76
77 /***********************************************************************
78  *              DrawDibOpen             [MSVFW32.@]
79  */
80 HDRAWDIB VFWAPI DrawDibOpen(void) 
81 {
82     WINE_HDD*   whdd;
83
84     TRACE("(void)\n");
85         
86     whdd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_HDD));
87     TRACE("=> %p\n", whdd);
88
89     while (MSVIDEO_GetHddPtr((HDRAWDIB)HDD_HandleRef) != NULL) HDD_HandleRef++;
90     whdd->hSelf = (HDRAWDIB)HDD_HandleRef++;
91
92     whdd->next = HDD_FirstHdd;
93     HDD_FirstHdd = whdd;
94
95     return whdd->hSelf;
96 }
97
98 /***********************************************************************
99  *              DrawDibClose            [MSVFW32.@]
100  */
101 BOOL VFWAPI DrawDibClose(HDRAWDIB hdd) 
102 {
103     WINE_HDD* whdd = MSVIDEO_GetHddPtr(hdd);
104     WINE_HDD** p;
105
106     TRACE("(%p)\n", hdd);
107
108     if (!whdd) return FALSE;
109
110     if (whdd->begun) DrawDibEnd(hdd);
111
112     for (p = &HDD_FirstHdd; *p != NULL; p = &((*p)->next))
113     {
114         if (*p == whdd)
115         {
116             *p = whdd->next;
117             break;
118         }
119     }
120
121     HeapFree(GetProcessHeap(), 0, whdd);
122
123     return TRUE;
124 }
125
126 /***********************************************************************
127  *              DrawDibEnd              [MSVFW32.@]
128  */
129 BOOL VFWAPI DrawDibEnd(HDRAWDIB hdd) 
130 {
131     BOOL ret = TRUE;
132     WINE_HDD *whdd = MSVIDEO_GetHddPtr(hdd);
133
134     TRACE("(%p)\n", hdd);
135
136     if (!whdd) return FALSE;
137
138     whdd->hpal = 0; /* Do not free this */
139     whdd->hdc = 0;
140     HeapFree(GetProcessHeap(), 0, whdd->lpbi);
141     whdd->lpbi = NULL;
142     HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
143     whdd->lpbiOut = NULL;
144
145     whdd->begun = FALSE;
146
147     /*if (whdd->lpvbits)
148       HeapFree(GetProcessHeap(), 0, whdd->lpvbuf);*/
149
150     if (whdd->hMemDC) 
151     {
152         SelectObject(whdd->hMemDC, whdd->hOldDib);
153         DeleteDC(whdd->hMemDC);
154         whdd->hMemDC = 0;
155     }
156
157     if (whdd->hDib) DeleteObject(whdd->hDib);
158     whdd->hDib = 0;
159
160     if (whdd->hic) 
161     {
162         ICDecompressEnd(whdd->hic);
163         ICClose(whdd->hic);
164         whdd->hic = 0;
165     }
166
167     whdd->lpvbits = NULL;
168
169     return ret;
170 }
171
172 /***********************************************************************
173  *              DrawDibBegin            [MSVFW32.@]
174  */
175 BOOL VFWAPI DrawDibBegin(HDRAWDIB hdd,
176                          HDC      hdc,
177                          INT      dxDst,
178                          INT      dyDst,
179                          LPBITMAPINFOHEADER lpbi,
180                          INT      dxSrc,
181                          INT      dySrc,
182                          UINT     wFlags) 
183 {
184     BOOL ret = TRUE;
185     WINE_HDD *whdd;
186
187     TRACE("(%p,%p,%d,%d,%p,%d,%d,0x%08x)\n",
188           hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, wFlags);
189
190     TRACE("lpbi: %d,%d/%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
191           lpbi->biSize, lpbi->biWidth, lpbi->biHeight, lpbi->biPlanes,
192           lpbi->biBitCount, lpbi->biCompression, lpbi->biSizeImage,
193           lpbi->biXPelsPerMeter, lpbi->biYPelsPerMeter, lpbi->biClrUsed,
194           lpbi->biClrImportant);
195
196     if (wFlags & ~(DDF_BUFFER))
197         FIXME("wFlags == 0x%08x not handled\n", wFlags & ~(DDF_BUFFER));
198
199     whdd = MSVIDEO_GetHddPtr(hdd);
200     if (!whdd) return FALSE;
201
202     if (whdd->begun) DrawDibEnd(hdd);
203
204     if (lpbi->biCompression) 
205     {
206         DWORD size = 0;
207
208         whdd->hic = ICOpen(ICTYPE_VIDEO, lpbi->biCompression, ICMODE_DECOMPRESS);
209         if (!whdd->hic) 
210         {
211             WARN("Could not open IC. biCompression == 0x%08x\n", lpbi->biCompression);
212             ret = FALSE;
213         }
214
215         if (ret) 
216         {
217             size = ICDecompressGetFormat(whdd->hic, lpbi, NULL);
218             if (size == ICERR_UNSUPPORTED) 
219             {
220                 WARN("Codec doesn't support GetFormat, giving up.\n");
221                 ret = FALSE;
222             }
223         }
224
225         if (ret) 
226         {
227             whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, size);
228
229             if (ICDecompressGetFormat(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
230                 ret = FALSE;
231         }
232
233         if (ret) 
234         {
235             /* FIXME: Use Ex functions if available? */
236             if (ICDecompressBegin(whdd->hic, lpbi, whdd->lpbiOut) != ICERR_OK)
237                 ret = FALSE;
238             
239             TRACE("biSizeImage == %d\n", whdd->lpbiOut->biSizeImage);
240             TRACE("biCompression == %d\n", whdd->lpbiOut->biCompression);
241             TRACE("biBitCount == %d\n", whdd->lpbiOut->biBitCount);
242         }
243     }
244     else 
245     {
246         DWORD dwSize;
247         /* No compression */
248         TRACE("Not compressed!\n");
249         dwSize = lpbi->biSize + num_colours(lpbi)*sizeof(RGBQUAD);
250         whdd->lpbiOut = HeapAlloc(GetProcessHeap(), 0, dwSize);
251         memcpy(whdd->lpbiOut, lpbi, dwSize);
252     }
253
254     if (ret) 
255     {
256         /*whdd->lpvbuf = HeapAlloc(GetProcessHeap(), 0, whdd->lpbiOut->biSizeImage);*/
257
258         whdd->hMemDC = CreateCompatibleDC(hdc);
259         TRACE("Creating: %d, %p\n", whdd->lpbiOut->biSize, whdd->lpvbits);
260         whdd->hDib = CreateDIBSection(whdd->hMemDC, (BITMAPINFO *)whdd->lpbiOut, DIB_RGB_COLORS, &(whdd->lpvbits), 0, 0);
261         if (whdd->hDib) 
262         {
263             TRACE("Created: %p,%p\n", whdd->hDib, whdd->lpvbits);
264         }
265         else
266         {
267             ret = FALSE;
268             TRACE("Error: %d\n", GetLastError());
269         }
270         whdd->hOldDib = SelectObject(whdd->hMemDC, whdd->hDib);
271     }
272
273     if (ret) 
274     {
275         whdd->hdc = hdc;
276         whdd->dxDst = dxDst;
277         whdd->dyDst = dyDst;
278         whdd->lpbi = HeapAlloc(GetProcessHeap(), 0, lpbi->biSize);
279         memcpy(whdd->lpbi, lpbi, lpbi->biSize);
280         whdd->dxSrc = dxSrc;
281         whdd->dySrc = dySrc;
282         whdd->begun = TRUE;
283         whdd->hpal = 0;
284     } 
285     else 
286     {
287         if (whdd->hic)
288             ICClose(whdd->hic);
289         HeapFree(GetProcessHeap(), 0, whdd->lpbiOut);
290         whdd->lpbiOut = NULL;
291     }
292
293     return ret;
294 }
295
296 /**********************************************************************
297  *              DrawDibDraw             [MSVFW32.@]
298  */
299 BOOL VFWAPI DrawDibDraw(HDRAWDIB hdd, HDC hdc,
300                         INT xDst, INT yDst, INT dxDst, INT dyDst,
301                         LPBITMAPINFOHEADER lpbi,
302                         LPVOID lpBits,
303                         INT xSrc, INT ySrc, INT dxSrc, INT dySrc,
304                         UINT wFlags)
305 {
306     WINE_HDD *whdd;
307     BOOL ret = TRUE;
308
309     TRACE("(%p,%p,%d,%d,%d,%d,%p,%p,%d,%d,%d,%d,0x%08x)\n",
310           hdd, hdc, xDst, yDst, dxDst, dyDst, lpbi, lpBits, xSrc, ySrc, dxSrc, dySrc, wFlags);
311
312     whdd = MSVIDEO_GetHddPtr(hdd);
313     if (!whdd) return FALSE;
314
315     TRACE("whdd=%p\n", whdd);
316
317     if (wFlags & ~(DDF_SAME_HDC | DDF_SAME_DRAW | DDF_NOTKEYFRAME | DDF_UPDATE | DDF_DONTDRAW | DDF_BACKGROUNDPAL))
318         FIXME("wFlags == 0x%08x not handled\n", wFlags);
319
320     if (!lpBits) 
321     {
322         /* Undocumented? */
323         lpBits = (LPSTR)lpbi + (WORD)(lpbi->biSize) + (WORD)(num_colours(lpbi)*sizeof(RGBQUAD));
324     }
325
326
327 #define CHANGED(x) (whdd->x != x)
328
329     if ((!whdd->begun) || 
330         (!(wFlags & DDF_SAME_HDC) && CHANGED(hdc)) || 
331         (!(wFlags & DDF_SAME_DRAW) && (CHANGED(lpbi) || CHANGED(dxSrc) || CHANGED(dySrc) || CHANGED(dxDst) || CHANGED(dyDst)))) 
332     {
333         TRACE("Something changed!\n");
334         ret = DrawDibBegin(hdd, hdc, dxDst, dyDst, lpbi, dxSrc, dySrc, 0);
335     }
336
337 #undef CHANGED
338
339     if ((dxDst == -1) && (dyDst == -1)) 
340     {
341         dxDst = dxSrc;
342         dyDst = dySrc;
343     }
344
345     if (!(wFlags & DDF_UPDATE)) 
346     {
347         DWORD biSizeImage = lpbi->biSizeImage;
348
349         /* biSizeImage may be set to 0 for BI_RGB (uncompressed) bitmaps */
350         if ((lpbi->biCompression == BI_RGB) && (biSizeImage == 0))
351             biSizeImage = ((lpbi->biWidth * lpbi->biBitCount + 31) / 32) * 4 * lpbi->biHeight;
352
353         if (lpbi->biCompression) 
354         {
355             DWORD flags = 0;
356
357             TRACE("Compression == 0x%08x\n", lpbi->biCompression);
358
359             if (wFlags & DDF_NOTKEYFRAME)
360                 flags |= ICDECOMPRESS_NOTKEYFRAME;
361
362             ICDecompress(whdd->hic, flags, lpbi, lpBits, whdd->lpbiOut, whdd->lpvbits);
363         }
364         else
365         {
366             memcpy(whdd->lpvbits, lpBits, biSizeImage);
367         }
368     }
369     if (!(wFlags & DDF_DONTDRAW) && whdd->hpal)
370     {
371         if ((wFlags & DDF_BACKGROUNDPAL) && ! (wFlags & DDF_SAME_HDC))
372          SelectPalette(hdc, whdd->hpal, TRUE);
373         else
374          SelectPalette(hdc, whdd->hpal, FALSE);
375     }
376
377     if (!(StretchBlt(whdd->hdc, xDst, yDst, dxDst, dyDst, whdd->hMemDC, xSrc, ySrc, dxSrc, dySrc, SRCCOPY)))
378         ret = FALSE;
379     
380     return ret;
381 }
382
383 /*************************************************************************
384  *              DrawDibStart            [MSVFW32.@]
385  */
386 BOOL VFWAPI DrawDibStart(HDRAWDIB hdd, DWORD rate) {
387         FIXME("(%p, %d), stub\n", hdd, rate);
388         return TRUE;
389 }
390
391 /*************************************************************************
392  *              DrawDibStop             [MSVFW32.@]
393  */
394 BOOL VFWAPI DrawDibStop(HDRAWDIB hdd) {
395         FIXME("(%p), stub\n", hdd);
396         return TRUE;
397 }
398
399 /***********************************************************************
400  *              DrawDibChangePalette       [MSVFW32.@]
401  */
402 BOOL VFWAPI DrawDibChangePalette(HDRAWDIB hdd, int iStart, int iLen, LPPALETTEENTRY lppe)
403 {
404     FIXME("(%p, 0x%08x, 0x%08x, %p), stub\n", hdd, iStart, iLen, lppe);
405     return TRUE;
406 }
407
408 /***********************************************************************
409  *              DrawDibSetPalette       [MSVFW32.@]
410  */
411 BOOL VFWAPI DrawDibSetPalette(HDRAWDIB hdd, HPALETTE hpal) 
412 {
413     WINE_HDD *whdd;
414
415     TRACE("(%p, %p)\n", hdd, hpal);
416
417     whdd = MSVIDEO_GetHddPtr(hdd);
418     if (!whdd) return FALSE;
419
420     whdd->hpal = hpal;
421
422     if (whdd->begun) 
423     {
424         SelectPalette(whdd->hdc, hpal, 0);
425         RealizePalette(whdd->hdc);
426     }
427
428     return TRUE;
429 }
430
431 /***********************************************************************
432  *              DrawDibGetBuffer       [MSVFW32.@]
433  */
434 LPVOID VFWAPI DrawDibGetBuffer(HDRAWDIB hdd, LPBITMAPINFOHEADER lpbi, DWORD dwSize, DWORD dwFlags)
435 {
436     FIXME("(%p, %p, 0x%08x, 0x%08x), stub\n", hdd, lpbi, dwSize, dwFlags);
437     return NULL;
438 }
439
440 /***********************************************************************
441  *              DrawDibGetPalette       [MSVFW32.@]
442  */
443 HPALETTE VFWAPI DrawDibGetPalette(HDRAWDIB hdd) 
444 {
445     WINE_HDD *whdd;
446
447     TRACE("(%p)\n", hdd);
448
449     whdd = MSVIDEO_GetHddPtr(hdd);
450     if (!whdd) return FALSE;
451
452     return whdd->hpal;
453 }
454
455 /***********************************************************************
456  *              DrawDibRealize          [MSVFW32.@]
457  */
458 UINT VFWAPI DrawDibRealize(HDRAWDIB hdd, HDC hdc, BOOL fBackground) 
459 {
460     WINE_HDD *whdd;
461     HPALETTE oldPal;
462     UINT ret = 0;
463
464     FIXME("(%p, %p, %d), stub\n", hdd, hdc, fBackground);
465
466     whdd = MSVIDEO_GetHddPtr(hdd);
467     if (!whdd) return FALSE;
468
469     if (!whdd || !(whdd->begun)) 
470     {
471         ret = 0;
472         goto out;
473     }
474
475     if (!whdd->hpal)
476         whdd->hpal = CreateHalftonePalette(hdc);
477
478     oldPal = SelectPalette(hdc, whdd->hpal, fBackground);
479     ret = RealizePalette(hdc);
480
481  out:
482     TRACE("=> %u\n", ret);
483     return ret;
484 }
485
486 /***********************************************************************
487  *              DrawDibTime          [MSVFW32.@]
488  */
489 BOOL VFWAPI DrawDibTime(HDRAWDIB hdd, LPDRAWDIBTIME lpddtime)
490 {
491     FIXME("(%p, %p) stub\n", hdd, lpddtime);
492     return FALSE;
493 }
494
495 /***********************************************************************
496  *              DrawDibProfileDisplay          [MSVFW32.@]
497  */
498 DWORD VFWAPI DrawDibProfileDisplay(LPBITMAPINFOHEADER lpbi)
499 {
500     FIXME("(%p) stub\n", lpbi);
501
502     return PD_CAN_DRAW_DIB;
503 }