Fixed bitmap range checking to avoid integer overflows.
[wine] / objects / brush.c
1 /*
2  * GDI brush objects
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <string.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "wine/wingdi16.h"
30 #include "bitmap.h"
31 #include "wownt32.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
35
36 /* GDI logical brush object */
37 typedef struct
38 {
39     GDIOBJHDR header;
40     LOGBRUSH  logbrush;
41 } BRUSHOBJ;
42
43 #define NB_HATCH_STYLES  6
44
45 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
46 static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
47 static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
48 static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj );
49
50 static const struct gdi_obj_funcs brush_funcs =
51 {
52     BRUSH_SelectObject,  /* pSelectObject */
53     BRUSH_GetObject16,   /* pGetObject16 */
54     BRUSH_GetObject,     /* pGetObjectA */
55     BRUSH_GetObject,     /* pGetObjectW */
56     NULL,                /* pUnrealizeObject */
57     BRUSH_DeleteObject   /* pDeleteObject */
58 };
59
60 static HGLOBAL16 dib_copy(BITMAPINFO *info, UINT coloruse)
61 {
62     BITMAPINFO  *newInfo;
63     HGLOBAL16   hmem;
64     INT         size;
65
66     if (info->bmiHeader.biCompression)
67         size = info->bmiHeader.biSizeImage;
68     else
69         size = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
70                                     info->bmiHeader.biHeight,
71                                     info->bmiHeader.biBitCount);
72     size += DIB_BitmapInfoSize( info, coloruse );
73
74     if (!(hmem = GlobalAlloc16( GMEM_MOVEABLE, size )))
75     {
76         return 0;
77     }
78     newInfo = (BITMAPINFO *) GlobalLock16( hmem );
79     memcpy( newInfo, info, size );
80     GlobalUnlock16( hmem );
81     return hmem;
82 }
83
84
85 /***********************************************************************
86  *           CreateBrushIndirect    (GDI32.@)
87  *
88  * BUGS
89  *      As for Windows 95 and Windows 98:
90  *      Creating brushes from bitmaps or DIBs larger than 8x8 pixels
91  *      is not supported. If a larger bitmap is given, only a portion
92  *      of the bitmap is used.
93  */
94 HBRUSH WINAPI CreateBrushIndirect( const LOGBRUSH * brush )
95 {
96     BRUSHOBJ * ptr;
97     HBRUSH hbrush;
98
99     if (!(ptr = GDI_AllocObject( sizeof(BRUSHOBJ), BRUSH_MAGIC,
100                                  (HGDIOBJ *)&hbrush, &brush_funcs ))) return 0;
101     ptr->logbrush.lbStyle = brush->lbStyle;
102     ptr->logbrush.lbColor = brush->lbColor;
103     ptr->logbrush.lbHatch = brush->lbHatch;
104
105     switch (ptr->logbrush.lbStyle)
106     {
107     case BS_PATTERN8X8:
108         ptr->logbrush.lbStyle = BS_PATTERN;
109         /* fall through */
110     case BS_PATTERN:
111         ptr->logbrush.lbHatch = (LONG)BITMAP_CopyBitmap( (HBITMAP) ptr->logbrush.lbHatch );
112         if (!ptr->logbrush.lbHatch) goto error;
113         break;
114
115     case BS_DIBPATTERNPT:
116         ptr->logbrush.lbStyle = BS_DIBPATTERN;
117         ptr->logbrush.lbHatch = (LONG)dib_copy( (BITMAPINFO *) ptr->logbrush.lbHatch,
118                                                 ptr->logbrush.lbColor);
119         if (!ptr->logbrush.lbHatch) goto error;
120         break;
121
122     case BS_DIBPATTERN8X8:
123     case BS_DIBPATTERN:
124        {
125             BITMAPINFO* bmi;
126             HGLOBAL h = (HGLOBAL)ptr->logbrush.lbHatch;
127
128             ptr->logbrush.lbStyle = BS_DIBPATTERN;
129             if (!(bmi = (BITMAPINFO *)GlobalLock( h ))) goto error;
130             ptr->logbrush.lbHatch = dib_copy( bmi, ptr->logbrush.lbColor);
131             GlobalUnlock( h );
132             if (!ptr->logbrush.lbHatch) goto error;
133             break;
134        }
135
136     default:
137         if(ptr->logbrush.lbStyle > BS_MONOPATTERN) goto error;
138         break;
139     }
140
141     GDI_ReleaseObj( hbrush );
142     TRACE("%p\n", hbrush);
143     return hbrush;
144
145  error:
146     GDI_FreeObject( hbrush, ptr );
147     return 0;
148 }
149
150
151 /***********************************************************************
152  *           CreateHatchBrush    (GDI32.@)
153  */
154 HBRUSH WINAPI CreateHatchBrush( INT style, COLORREF color )
155 {
156     LOGBRUSH logbrush;
157
158     TRACE("%d %06lx\n", style, color );
159
160     logbrush.lbStyle = BS_HATCHED;
161     logbrush.lbColor = color;
162     logbrush.lbHatch = style;
163
164     return CreateBrushIndirect( &logbrush );
165 }
166
167
168 /***********************************************************************
169  *           CreatePatternBrush    (GDI32.@)
170  */
171 HBRUSH WINAPI CreatePatternBrush( HBITMAP hbitmap )
172 {
173     LOGBRUSH logbrush = { BS_PATTERN, 0, 0 };
174     TRACE("%p\n", hbitmap );
175
176     logbrush.lbHatch = (ULONG_PTR)hbitmap;
177     return CreateBrushIndirect( &logbrush );
178 }
179
180
181 /***********************************************************************
182  *           CreateDIBPatternBrush    (GDI32.@)
183  *
184  *      Create a logical brush which has the pattern specified by the DIB
185  *
186  *      Function call is for compatibility only.  CreateDIBPatternBrushPt should be used.
187  *
188  * RETURNS
189  *
190  *      Handle to a logical brush on success, NULL on failure.
191  *
192  * BUGS
193  *
194  */
195 HBRUSH WINAPI CreateDIBPatternBrush(
196                 HGLOBAL hbitmap, /* [in] Global object containg BITMAPINFO structure */
197                 UINT coloruse    /* [in] Specifies color format, if provided */
198 )
199 {
200     LOGBRUSH logbrush;
201
202     TRACE("%p\n", hbitmap );
203
204     logbrush.lbStyle = BS_DIBPATTERN;
205     logbrush.lbColor = coloruse;
206
207     logbrush.lbHatch = (LONG)hbitmap;
208
209     return CreateBrushIndirect( &logbrush );
210 }
211
212
213 /***********************************************************************
214  *           CreateDIBPatternBrushPt    (GDI32.@)
215  *
216  *      Create a logical brush which has the pattern specified by the DIB
217  *
218  * RETURNS
219  *
220  *      Handle to a logical brush on success, NULL on failure.
221  *
222  * BUGS
223  *
224  */
225 HBRUSH WINAPI CreateDIBPatternBrushPt(
226                 const void* data, /* [in] Pointer to a BITMAPINFO structure followed by more data */
227                 UINT coloruse     /* [in] Specifies color format, if provided */
228 )
229 {
230     BITMAPINFO *info=(BITMAPINFO*)data;
231     LOGBRUSH logbrush;
232
233     if (!data)
234         return NULL;
235
236     TRACE("%p %ldx%ld %dbpp\n", info, info->bmiHeader.biWidth,
237           info->bmiHeader.biHeight,  info->bmiHeader.biBitCount);
238
239     logbrush.lbStyle = BS_DIBPATTERNPT;
240     logbrush.lbColor = coloruse;
241     logbrush.lbHatch = (LONG) data;
242
243     return CreateBrushIndirect( &logbrush );
244 }
245
246
247 /***********************************************************************
248  *           CreateSolidBrush    (GDI32.@)
249  */
250 HBRUSH WINAPI CreateSolidBrush( COLORREF color )
251 {
252     LOGBRUSH logbrush;
253
254     TRACE("%06lx\n", color );
255
256     logbrush.lbStyle = BS_SOLID;
257     logbrush.lbColor = color;
258     logbrush.lbHatch = 0;
259
260     return CreateBrushIndirect( &logbrush );
261 }
262
263
264 /***********************************************************************
265  *           SetBrushOrgEx    (GDI32.@)
266  */
267 BOOL WINAPI SetBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
268 {
269     DC *dc = DC_GetDCPtr( hdc );
270
271     if (!dc) return FALSE;
272     if (oldorg)
273     {
274         oldorg->x = dc->brushOrgX;
275         oldorg->y = dc->brushOrgY;
276     }
277     dc->brushOrgX = x;
278     dc->brushOrgY = y;
279     GDI_ReleaseObj( hdc );
280     return TRUE;
281 }
282
283 /***********************************************************************
284  *           FixBrushOrgEx    (GDI32.@)
285  * SDK says discontinued, but in Win95 GDI32 this is the same as SetBrushOrgEx
286  */
287 BOOL WINAPI FixBrushOrgEx( HDC hdc, INT x, INT y, LPPOINT oldorg )
288 {
289     return SetBrushOrgEx(hdc,x,y,oldorg);
290 }
291
292
293 /***********************************************************************
294  *           BRUSH_SelectObject
295  */
296 static HGDIOBJ BRUSH_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
297 {
298     BRUSHOBJ *brush = obj;
299     HGDIOBJ ret;
300     DC *dc = DC_GetDCPtr( hdc );
301
302     if (!dc) return 0;
303
304     if (brush->logbrush.lbStyle == BS_PATTERN)
305         BITMAP_SetOwnerDC( (HBITMAP)brush->logbrush.lbHatch, dc );
306
307     ret = dc->hBrush;
308     if (dc->funcs->pSelectBrush) handle = dc->funcs->pSelectBrush( dc->physDev, handle );
309     if (handle) dc->hBrush = handle;
310     else ret = 0;
311     GDI_ReleaseObj( hdc );
312     return ret;
313 }
314
315
316 /***********************************************************************
317  *           BRUSH_DeleteObject
318  */
319 static BOOL BRUSH_DeleteObject( HGDIOBJ handle, void *obj )
320 {
321     BRUSHOBJ *brush = obj;
322
323     switch(brush->logbrush.lbStyle)
324     {
325       case BS_PATTERN:
326           DeleteObject( (HGDIOBJ)brush->logbrush.lbHatch );
327           break;
328       case BS_DIBPATTERN:
329           GlobalFree16( (HGLOBAL16)brush->logbrush.lbHatch );
330           break;
331     }
332     return GDI_FreeObject( handle, obj );
333 }
334
335
336 /***********************************************************************
337  *           BRUSH_GetObject16
338  */
339 static INT BRUSH_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
340 {
341     BRUSHOBJ *brush = obj;
342     LOGBRUSH16 logbrush;
343
344     logbrush.lbStyle = brush->logbrush.lbStyle;
345     logbrush.lbColor = brush->logbrush.lbColor;
346     logbrush.lbHatch = brush->logbrush.lbHatch;
347     if (count > sizeof(logbrush)) count = sizeof(logbrush);
348     memcpy( buffer, &logbrush, count );
349     return count;
350 }
351
352
353 /***********************************************************************
354  *           BRUSH_GetObject
355  */
356 static INT BRUSH_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
357 {
358     BRUSHOBJ *brush = obj;
359
360     if( !buffer )
361         return sizeof(brush->logbrush);
362
363     if (count > sizeof(brush->logbrush)) count = sizeof(brush->logbrush);
364     memcpy( buffer, &brush->logbrush, count );
365     return count;
366 }
367
368
369 /***********************************************************************
370  *           SetSolidBrush   (GDI.604)
371  *
372  *  If hBrush is a solid brush, change its color to newColor.
373  *
374  *  RETURNS
375  *           TRUE on success, FALSE on failure.
376  *
377  *  FIXME: untested, not sure if correct.
378  */
379 BOOL16 WINAPI SetSolidBrush16(HBRUSH16 hBrush, COLORREF newColor )
380 {
381     BRUSHOBJ * brushPtr;
382     BOOL16 res = FALSE;
383
384     TRACE("(hBrush %04x, newColor %08lx)\n", hBrush, (DWORD)newColor);
385     if (!(brushPtr = (BRUSHOBJ *) GDI_GetObjPtr( HBRUSH_32(hBrush), BRUSH_MAGIC )))
386         return FALSE;
387
388     if (brushPtr->logbrush.lbStyle == BS_SOLID)
389     {
390         brushPtr->logbrush.lbColor = newColor;
391         res = TRUE;
392     }
393
394      GDI_ReleaseObj( HBRUSH_32(hBrush) );
395      return res;
396 }