diff --git a/dlls/gdi32/dib.c b/dlls/gdi32/dib.c index 65e9e1b8ea7..7ab2982c8f6 100644 --- a/dlls/gdi32/dib.c +++ b/dlls/gdi32/dib.c @@ -180,7 +180,7 @@ static BOOL bitmapinfo_from_user_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO * src_colors = (char *)info + info->bmiHeader.biSize; colors = get_dib_num_of_colors( dst ); - if (info->bmiHeader.biCompression == BI_BITFIELDS) + if (dst->bmiHeader.biCompression == BI_BITFIELDS) { /* bitfields are always at bmiColors even in larger structures */ memcpy( dst->bmiColors, info->bmiColors, 3 * sizeof(DWORD) ); @@ -929,6 +929,9 @@ INT WINAPI GetDIBits( /* Since info may be a BITMAPCOREINFO or any of the larger BITMAPINFO structures, we'll use our own copy and transfer the colour info back at the end */ if (!bitmapinfoheader_from_user_bitmapinfo( &dst_info->bmiHeader, &info->bmiHeader )) return 0; + if (bits && + (dst_info->bmiHeader.biCompression == BI_JPEG || dst_info->bmiHeader.biCompression == BI_PNG)) + return 0; dst_info->bmiHeader.biClrUsed = 0; dst_info->bmiHeader.biClrImportant = 0; @@ -946,12 +949,6 @@ INT WINAPI GetDIBits( funcs = get_bitmap_funcs( bmp ); - if (dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */ - { - ret = fill_query_info( info, bmp ); - goto done; - } - src.visrect.left = 0; src.visrect.top = 0; src.visrect.right = bmp->bitmap.bmWidth; @@ -965,6 +962,45 @@ INT WINAPI GetDIBits( if (lines == 0 || startscan >= dst.visrect.bottom) bits = NULL; + if (!bits && dst_info->bmiHeader.biBitCount == 0) /* query bitmap info only */ + { + ret = fill_query_info( info, bmp ); + goto done; + } + + /* validate parameters */ + + if (dst_info->bmiHeader.biWidth <= 0) goto done; + if (dst_info->bmiHeader.biHeight == 0) goto done; + + switch (dst_info->bmiHeader.biCompression) + { + case BI_RLE4: + if (dst_info->bmiHeader.biBitCount != 4) goto done; + if (dst_info->bmiHeader.biHeight < 0) goto done; + if (bits) goto done; /* can't retrieve compressed bits */ + break; + case BI_RLE8: + if (dst_info->bmiHeader.biBitCount != 8) goto done; + if (dst_info->bmiHeader.biHeight < 0) goto done; + if (bits) goto done; /* can't retrieve compressed bits */ + break; + case BI_BITFIELDS: + if (dst_info->bmiHeader.biBitCount != 16 && dst_info->bmiHeader.biBitCount != 32) goto done; + /* fall through */ + case BI_RGB: + if (lines && !dst_info->bmiHeader.biPlanes) goto done; + if (dst_info->bmiHeader.biBitCount == 1) break; + if (dst_info->bmiHeader.biBitCount == 4) break; + if (dst_info->bmiHeader.biBitCount == 8) break; + if (dst_info->bmiHeader.biBitCount == 16) break; + if (dst_info->bmiHeader.biBitCount == 24) break; + if (dst_info->bmiHeader.biBitCount == 32) break; + /* fall through */ + default: + goto done; + } + if (bits) { if (dst_info->bmiHeader.biHeight > 0) diff --git a/dlls/gdi32/tests/bitmap.c b/dlls/gdi32/tests/bitmap.c index 7e3ddc9499f..d5a39bebf93 100644 --- a/dlls/gdi32/tests/bitmap.c +++ b/dlls/gdi32/tests/bitmap.c @@ -884,9 +884,27 @@ static void test_dib_formats(void) case 32: expect_ok = (compr == BI_RGB || compr == BI_BITFIELDS); break; default: expect_ok = FALSE; break; } - if (!planes) expect_ok = FALSE; todo = (compr == BI_BITFIELDS); /* wine doesn't like strange bitfields */ + memset( bi, 0, sizeof(bi->bmiHeader) ); + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi->bmiHeader.biWidth = 2; + bi->bmiHeader.biHeight = 2; + bi->bmiHeader.biPlanes = planes; + bi->bmiHeader.biBitCount = bpp; + bi->bmiHeader.biCompression = compr; + bi->bmiHeader.biSizeImage = 0; + memset( bi->bmiColors, 0xaa, sizeof(RGBQUAD) * 256 ); + ret = GetDIBits(hdc, hbmp, 0, 0, data, bi, DIB_RGB_COLORS); + if (expect_ok || (!bpp && compr != BI_JPEG && compr != BI_PNG) || + (bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)) + ok( ret, "GetDIBits failed for %u/%u/%u\n", bpp, planes, compr ); + else + ok( !ret || broken(!bpp && (compr == BI_JPEG || compr == BI_PNG)), /* nt4 */ + "GetDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); + + /* all functions check planes except GetDIBits with 0 lines */ + if (!planes) expect_ok = FALSE; memset( bi, 0, sizeof(bi->bmiHeader) ); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi->bmiHeader.biWidth = 2; @@ -947,9 +965,27 @@ static void test_dib_formats(void) broken((bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)), /* nt4 */ "StretchDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); + ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS); + if (expect_ok) + ok( ret, "GetDIBits failed for %u/%u/%u\n", bpp, planes, compr ); + else + ok( !ret, "GetDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); + ok( bi->bmiHeader.biBitCount == bpp, "GetDIBits modified bpp %u/%u\n", + bpp, bi->bmiHeader.biBitCount ); + + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi->bmiHeader.biWidth = 2; + bi->bmiHeader.biHeight = 2; + bi->bmiHeader.biPlanes = planes; + bi->bmiHeader.biBitCount = bpp; + bi->bmiHeader.biCompression = compr; bi->bmiHeader.biSizeImage = 1; + memset( bi->bmiColors, 0xaa, sizeof(RGBQUAD) * 256 ); + /* RLE allowed with valid biSizeImage */ + if ((bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)) expect_ok = TRUE; + ret = SetDIBits(hdc, hbmp, 0, 1, data, bi, DIB_RGB_COLORS); - if (expect_ok || (bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)) + if (expect_ok) { if (todo) todo_wine ok( ret, "SetDIBits failed for %u/%u/%u\n", bpp, planes, compr ); @@ -959,12 +995,12 @@ static void test_dib_formats(void) else ok( !ret, "SetDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); ret = SetDIBitsToDevice( memdc, 0, 0, 1, 1, 0, 0, 0, 1, data, bi, DIB_RGB_COLORS ); - if (expect_ok || (bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)) + if (expect_ok) ok( ret, "SetDIBitsToDevice failed for %u/%u/%u\n", bpp, planes, compr ); else ok( !ret, "SetDIBitsToDevice succeeded for %u/%u/%u\n", bpp, planes, compr ); ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY ); - if (expect_ok || (bpp == 4 && compr == BI_RLE4) || (bpp == 8 && compr == BI_RLE8)) + if (expect_ok) { if (todo) todo_wine ok( ret, "StretchDIBits failed for %u/%u/%u\n", bpp, planes, compr ); @@ -973,6 +1009,13 @@ static void test_dib_formats(void) } else ok( !ret, "StretchDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); + + bi->bmiHeader.biSizeImage = 0; + ret = GetDIBits(hdc, hbmp, 0, 2, NULL, bi, DIB_RGB_COLORS); + if (expect_ok || !bpp) + ok( ret, "GetDIBits failed for %u/%u/%u\n", bpp, planes, compr ); + else + ok( !ret, "GetDIBits succeeded for %u/%u/%u\n", bpp, planes, compr ); } } } @@ -1001,6 +1044,17 @@ static void test_dib_formats(void) ok( ret, "SetDIBitsToDevice failed with null bitfields\n" ); ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY ); todo_wine ok( ret, "StretchDIBits failed with null bitfields\n" ); + ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS); + ok( ret, "GetDIBits failed with null bitfields\n" ); + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 16; + bi->bmiHeader.biCompression = BI_BITFIELDS; + bi->bmiHeader.biSizeImage = 0; + *(DWORD *)&bi->bmiColors[0] = 0; + *(DWORD *)&bi->bmiColors[1] = 0; + *(DWORD *)&bi->bmiColors[2] = 0; + ret = GetDIBits(hdc, hbmp, 0, 2, NULL, bi, DIB_RGB_COLORS); + ok( ret, "GetDIBits failed with null bitfields\n" ); /* all fields must be non-zero */ *(DWORD *)&bi->bmiColors[0] = 3; @@ -1035,6 +1089,14 @@ static void test_dib_formats(void) ok( !ret, "SetDIBitsToDevice succeeded with negative width\n" ); ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY ); ok( !ret, "StretchDIBits succeeded with negative width\n" ); + ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS); + ok( !ret, "GetDIBits succeeded with negative width\n" ); + bi->bmiHeader.biWidth = -2; + bi->bmiHeader.biHeight = 2; + bi->bmiHeader.biBitCount = 32; + bi->bmiHeader.biCompression = BI_RGB; + ret = GetDIBits(hdc, hbmp, 0, 2, NULL, bi, DIB_RGB_COLORS); + ok( !ret || broken(ret), /* nt4 */ "GetDIBits succeeded with negative width\n" ); bi->bmiHeader.biWidth = 0; bi->bmiHeader.biHeight = 2; @@ -1051,6 +1113,14 @@ static void test_dib_formats(void) ok( !ret || broken(ret), /* nt4 */ "SetDIBitsToDevice succeeded with zero width\n" ); ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY ); ok( !ret || broken(ret), /* nt4 */ "StretchDIBits succeeded with zero width\n" ); + ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS); + ok( !ret, "GetDIBits succeeded with zero width\n" ); + bi->bmiHeader.biWidth = 0; + bi->bmiHeader.biHeight = 2; + bi->bmiHeader.biBitCount = 32; + bi->bmiHeader.biCompression = BI_RGB; + ret = GetDIBits(hdc, hbmp, 0, 2, NULL, bi, DIB_RGB_COLORS); + ok( !ret || broken(ret), /* nt4 */ "GetDIBits succeeded with zero width\n" ); bi->bmiHeader.biWidth = 2; bi->bmiHeader.biHeight = 0; @@ -1067,6 +1137,14 @@ static void test_dib_formats(void) ok( !ret, "SetDIBitsToDevice succeeded with zero height\n" ); ret = StretchDIBits( memdc, 0, 0, 1, 1, 0, 0, 1, 1, data, bi, DIB_RGB_COLORS, SRCCOPY ); ok( !ret, "StretchDIBits succeeded with zero height\n" ); + ret = GetDIBits(hdc, hbmp, 0, 2, data, bi, DIB_RGB_COLORS); + ok( !ret || broken(ret), /* nt4 */ "GetDIBits succeeded with zero height\n" ); + bi->bmiHeader.biWidth = 2; + bi->bmiHeader.biHeight = 0; + bi->bmiHeader.biBitCount = 32; + bi->bmiHeader.biCompression = BI_RGB; + ret = GetDIBits(hdc, hbmp, 0, 2, NULL, bi, DIB_RGB_COLORS); + ok( !ret || broken(ret), /* nt4 */ "GetDIBits succeeded with zero height\n" ); DeleteDC( memdc ); DeleteObject( hbmp );