diff --git a/modules/rostests/apitests/gdi32/SetDIBitsToDevice.c b/modules/rostests/apitests/gdi32/SetDIBitsToDevice.c index 6e35b0d0afe..e8ce3830205 100644 --- a/modules/rostests/apitests/gdi32/SetDIBitsToDevice.c +++ b/modules/rostests/apitests/gdi32/SetDIBitsToDevice.c @@ -129,7 +129,7 @@ Test_SetDIBitsToDevice_Params() (BYTE*)aulBits + 1, // lpvBits, pbmi, DIB_RGB_COLORS); - todo_ros ok_dec(ret, 0); + ok_dec(ret, 0); ok_err(0xdeadc0de); /* test unaligned illegal buffer */ @@ -146,7 +146,7 @@ Test_SetDIBitsToDevice_Params() (BYTE*)0x7fffffff, // lpvBits, pbmi, DIB_RGB_COLORS); - todo_ros ok_dec(ret, 0); + ok_dec(ret, 0); ok_err(0xdeadc0de); /* Test negative XDest */ @@ -248,7 +248,7 @@ Test_SetDIBitsToDevice_Params() aulBits, // lpvBits, pbmi, DIB_RGB_COLORS); - todo_ros ok_dec(ret, 7); + ok_dec(ret, 7); ok_err(0xdeadc0de); /* Test large cScanlines */ @@ -265,7 +265,7 @@ Test_SetDIBitsToDevice_Params() aulBits, // lpvBits, pbmi, DIB_RGB_COLORS); - todo_ros ok_dec(ret, 0); + ok_dec(ret, 0); ok_err(0xdeadc0de); /* Test uStartScan and cScanLines larger than the DIB */ diff --git a/win32ss/gdi/gdi32/objects/bitmap.c b/win32ss/gdi/gdi32/objects/bitmap.c index 438521f69e9..1cdd9e34163 100644 --- a/win32ss/gdi/gdi32/objects/bitmap.c +++ b/win32ss/gdi/gdi32/objects/bitmap.c @@ -209,6 +209,12 @@ CreateDIBSection( HBITMAP hBitmap = NULL; PVOID bmBits = NULL; + if (Usage != DIB_PAL_COLORS && Usage != DIB_RGB_COLORS) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + pConvertedInfo = ConvertBitmapInfo(BitmapInfo, Usage, &ConvertedInfoSize, FALSE); @@ -574,9 +580,12 @@ SetDIBits( DWORD dwWidth, dwHeight; HGDIOBJ hOldBitmap; HPALETTE hPal = NULL; - INT LinesCopied = 0; + INT LinesCopied = 0, LinesReturned = 0; BOOL newDC = FALSE; + if (fuColorUse != DIB_PAL_COLORS && fuColorUse != DIB_RGB_COLORS) + return 0; + if (!lpvBits || (GDI_HANDLE_GET_TYPE(hBitmap) != GDI_OBJECT_TYPE_BITMAP)) return 0; @@ -588,6 +597,33 @@ SetDIBits( SetLastError(ERROR_INVALID_PARAMETER); return 0; } + + if (lpbmi->bmiHeader.biCompression == BI_RLE4 + || lpbmi->bmiHeader.biCompression == BI_RLE8) + { + if (cScanLines == 0) + return 0; + else + LinesCopied = abs(lpbmi->bmiHeader.biHeight); + + if ((lpbmi->bmiHeader.biHeight > 0) && cScanLines == 0) + { + LinesCopied = min(cScanLines, abs(lpbmi->bmiHeader.biHeight) - uStartScan); + } + } + else + { + if (lpbmi->bmiHeader.biHeight > 0) + { + /* For top-down case, Windows limits lines. */ + LinesCopied = min(cScanLines, abs(lpbmi->bmiHeader.biHeight) - uStartScan); + } + else + { + /* Unlike the bottom-up case, Windows doesn't limit lines. */ + LinesCopied = min(cScanLines, abs(lpbmi->bmiHeader.biHeight)); + } + } } hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap. @@ -622,7 +658,7 @@ SetDIBits( dwHeight = abs(lpbmi->bmiHeader.biHeight); } - LinesCopied = SetDIBitsToDevice(SavehDC, 0, 0, dwWidth, dwHeight, 0, 0, uStartScan, + LinesReturned = SetDIBitsToDevice(SavehDC, 0, 0, dwWidth, dwHeight, 0, 0, uStartScan, cScanLines, (void *) lpvBits, (LPBITMAPINFO) lpbmi, fuColorUse); if (hDC) @@ -636,6 +672,9 @@ SetDIBits( else RestoreDC(SavehDC, -1); + if (LinesReturned == 0) + return 0; + return LinesCopied; } @@ -662,12 +701,18 @@ SetDIBitsToDevice( PDC_ATTR pDc_Attr; PBITMAPINFO pConvertedInfo; UINT ConvertedInfoSize; - INT LinesCopied = 0; + INT LinesCopied = 0, LinesReturned = 0, src_y = 0; UINT cjBmpScanSize = 0; - BOOL Hit = FALSE; + BOOL Hit = FALSE, Hit2= FALSE; PVOID pvSafeBits = (PVOID) Bits; - - if (!ScanLines || !lpbmi || !Bits) + // VMware maximum resolution is 2048 x 1536 + INT MaxScreenLines = 1536; + // Arbitrary number for Maximum StartScan + INT MaxStartScan = LONG_MAX / 2; + BOOL top_down; + UINT height; + + if (!ScanLines || !lpbmi || !Bits || (Height == 0)) return 0; if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1) @@ -677,6 +722,46 @@ SetDIBitsToDevice( if (!pConvertedInfo) return 0; + top_down = (pConvertedInfo->bmiHeader.biHeight < 0); + height = abs(pConvertedInfo->bmiHeader.biHeight); + + if (pConvertedInfo->bmiHeader.biHeight == 0) + { + return 0; + } + + // If DIB Height is big negative amd StartScan not huge + if ((lpbmi->bmiHeader.biHeight < -MaxScreenLines) && + (StartScan < MaxStartScan)) + { + return ScanLines; + } + + // If ScanLines are huge positive + if ((ScanLines > MaxScreenLines) || (lpbmi->bmiHeader.biHeight > MaxScreenLines)) + { + LinesCopied = 0; + goto Exit; + } + + // If DIB height > Height and lpbmi biHeight not too big + if ((ScanLines > MaxScreenLines) || (abs(lpbmi->bmiHeader.biHeight) > MaxScreenLines)) + { + LinesCopied = 0; + goto Exit; + } + + if ((pConvertedInfo->bmiHeader.biCompression != BI_RLE8) && + (pConvertedInfo->bmiHeader.biCompression != BI_RLE4)) + { + // If ScanLines > DIB + if (ScanLines > abs(lpbmi->bmiHeader.biHeight)) + { + LinesCopied = ScanLines; + goto Exit; + } + } + HANDLE_METADC(INT, SetDIBitsToDevice, 0, @@ -726,7 +811,36 @@ SetDIBitsToDevice( { /* For compressed data, we must set the whole thing */ StartScan = 0; - ScanLines = pConvertedInfo->bmiHeader.biHeight; + ScanLines = height; + LinesCopied = height; + return height; + } + else + { + if (StartScan >= height) return 0; + if (!top_down && ScanLines > height - StartScan) + ScanLines = height - StartScan; + + if (pConvertedInfo->bmiHeader.biHeight > 0) + { + src_y = StartScan + ScanLines - (YSrc + Height); + if (src_y > 0) + { + if (!top_down) + { + /* get rid of unnecessary lines */ + if (src_y >= ScanLines) return 0; + ScanLines -= src_y; + } + else if (src_y >= ScanLines) return ScanLines; + } + LinesCopied = ScanLines; + } + else + { + /* Unlike the bottom-up case, Windows doesn't limit lines. */ + LinesCopied = min(ScanLines, abs(pConvertedInfo->bmiHeader.biHeight)); + } } cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, ScanLines); @@ -742,14 +856,42 @@ SetDIBitsToDevice( { Hit = TRUE; } - _SEH2_END + _SEH2_END; + + /* The caller might be sending "just enough" data. Setting ScanLines as Height */ + if ((ScanLines > Height) && (StartScan < MaxStartScan)) + { + ScanLines = Height; + cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, Height); + } if (Hit) { // We don't die, we continue on with a allocated safe pointer to kernel // space..... - DPRINT1("SetDIBitsToDevice fail to read BitMapInfo: %p or Bits: %p & Size: %u\n", - pConvertedInfo, Bits, cjBmpScanSize); + + DPRINT("SetDIBitsToDevice fail to read BitMapInfo: %p or Bits: %p & Size: %u Height: %u ScanLines: %u.\n", + pConvertedInfo, Bits, cjBmpScanSize, Height, ScanLines); + _SEH2_TRY + { + RtlCopyMemory(pvSafeBits, Bits, cjBmpScanSize); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + Hit2 = TRUE; + } + _SEH2_END; + if (Hit) + { + DPRINT("SetDIBitsToDevice second fail.\n"); + } + // Cannot read either + if (Hit && Hit2) + { + LinesCopied = 0; + goto Exit; + } + } DPRINT("SetDIBitsToDevice Allocate Bits %u!!!\n", cjBmpScanSize); } @@ -766,12 +908,16 @@ SetDIBitsToDevice( (pConvertedInfo->bmiHeader.biCompression == BI_JPEG || pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/ { - LinesCopied = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest, Width, Height, XSrc, YSrc, + LinesReturned = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest, Width, Height, XSrc, YSrc, StartScan, ScanLines, (LPBYTE) pvSafeBits, (LPBITMAPINFO) pConvertedInfo, ColorUse, cjBmpScanSize, ConvertedInfoSize, TRUE, NULL); } + + if (LinesReturned == 0) + LinesCopied = 0; + Exit: if (Bits != pvSafeBits) RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits); @@ -837,6 +983,16 @@ StretchDIBits( return 0; } + if (pConvertedInfo->bmiHeader.biWidth < 0) + { + return 0; + } + + if (pConvertedInfo->bmiHeader.biHeight == 0) + { + return 0; + } + cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) pConvertedInfo); if (lpBits)