[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / dibobj.c
index d91d8e4..2178bff 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:         ReactOS win32 kernel mode subsystem
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            subsystems/win32/win32k/objects/dibobj.c
+ * FILE:            win32ss/gdi/ntgdi/dibobj.c
  * PURPOSE:         Dib object functions
  * PROGRAMMER:
  */
@@ -248,6 +248,7 @@ IntSetDIBits(
     UINT  StartScan,
     UINT  ScanLines,
     CONST VOID  *Bits,
+    ULONG cjMaxBits,
     CONST BITMAPINFO  *bmi,
     UINT  ColorUse)
 {
@@ -258,8 +259,39 @@ IntSetDIBits(
     POINTL             ptSrc;
     EXLATEOBJ  exlo;
     PPALETTE    ppalDIB = 0;
+    ULONG cjSizeImage;
 
-    if (!bmi) return 0;
+    if (!bmi || !Bits) return 0;
+
+    /* Check for uncompressed formats */
+    if ((bmi->bmiHeader.biCompression == BI_RGB) ||
+             (bmi->bmiHeader.biCompression == BI_BITFIELDS))
+    {
+        /* Calculate the image size */
+        cjSizeImage = DIB_GetDIBImageBytes(bmi->bmiHeader.biWidth,
+                                           ScanLines,
+                                           bmi->bmiHeader.biBitCount);
+    }
+    /* Check if the header provided an image size */
+    else if (bmi->bmiHeader.biSizeImage != 0)
+    {
+        /* Use the given size */
+        cjSizeImage = bmi->bmiHeader.biSizeImage;
+    }
+    else
+    {
+        /* Compressed format without a size. This is invalid. */
+        DPRINT1("Compressed format without a size!");
+        return 0;
+    }
+
+    /* Check if the size that we have is ok */
+    if ((cjSizeImage > cjMaxBits) || (cjSizeImage == 0))
+    {
+        DPRINT1("Invalid bitmap size! cjSizeImage = %lu, cjMaxBits = %lu\n",
+                cjSizeImage, cjMaxBits);
+        return 0;
+    }
 
     SourceBitmap = GreCreateBitmapEx(bmi->bmiHeader.biWidth,
                                      ScanLines,
@@ -267,7 +299,7 @@ IntSetDIBits(
                                      BitmapFormat(bmi->bmiHeader.biBitCount,
                                                   bmi->bmiHeader.biCompression),
                                      bmi->bmiHeader.biHeight < 0 ? BMF_TOPDOWN : 0,
-                                     bmi->bmiHeader.biSizeImage,
+                                     cjSizeImage,
                                      (PVOID)Bits,
                                      0);
     if (!SourceBitmap)
@@ -309,6 +341,8 @@ IntSetDIBits(
     ptSrc.x = 0;
     ptSrc.y = 0;
 
+    NT_ASSERT(psurfSrc->SurfObj.cjBits <= cjMaxBits);
+
     result = IntEngCopyBits(&psurfDst->SurfObj,
                             &psurfSrc->SurfObj,
                             NULL,
@@ -461,7 +495,7 @@ NtGdiSetDIBitsToDeviceInternal(
 {
     INT ret = 0;
     NTSTATUS Status = STATUS_SUCCESS;
-    PDC pDC;
+    PDC pDC = NULL;
     HBITMAP hSourceBitmap = NULL, hMaskBitmap = NULL;
     SURFOBJ *pDestSurf, *pSourceSurf = NULL, *pMaskSurf = NULL;
     SURFACE *pSurf;
@@ -493,21 +527,25 @@ NtGdiSetDIBitsToDeviceInternal(
 
     if (!NT_SUCCESS(Status))
     {
-        goto Exit2;
+        goto Exit;
     }
 
     ScanLines = min(ScanLines, abs(bmi->bmiHeader.biHeight) - StartScan);
+    if (ScanLines == 0)
+    {
+        DPRINT1("ScanLines == 0\n");
+        goto Exit;
+    }
 
     pDC = DC_LockDc(hDC);
     if (!pDC)
     {
         EngSetLastError(ERROR_INVALID_HANDLE);
-        goto Exit2;
+        goto Exit;
     }
 
     if (pDC->dctype == DC_TYPE_INFO)
     {
-        DC_UnlockDc(pDC);
         goto Exit;
     }
 
@@ -637,14 +675,13 @@ Exit:
     }
 
     if (ppalDIB) PALETTE_ShareUnlockPalette(ppalDIB);
-
     if (pSourceSurf) EngUnlockSurface(pSourceSurf);
     if (hSourceBitmap) EngDeleteSurface((HSURF)hSourceBitmap);
     if (pMaskSurf) EngUnlockSurface(pMaskSurf);
     if (hMaskBitmap) EngDeleteSurface((HSURF)hMaskBitmap);
-    DC_UnlockDc(pDC);
-Exit2:
+    if (pDC) DC_UnlockDc(pDC);
     ExFreePoolWithTag(pbmiSafe, 'pmTG');
+
     return ret;
 }
 
@@ -674,7 +711,7 @@ GreGetDIBitsInternal(
     RGBQUAD* rgbQuads;
     VOID* colorPtr;
 
-    DPRINT("Entered NtGdiGetDIBitsInternal()\n");
+    DPRINT("Entered GreGetDIBitsInternal()\n");
 
     if ((Usage && Usage != DIB_PAL_COLORS) || !Info || !hBitmap)
         return 0;
@@ -999,6 +1036,8 @@ done:
     return ScanLines;
 }
 
+_Success_(return!=0)
+__kernel_entry
 INT
 APIENTRY
 NtGdiGetDIBitsInternal(
@@ -1006,13 +1045,13 @@ NtGdiGetDIBitsInternal(
     _In_ HBITMAP hbm,
     _In_ UINT iStartScan,
     _In_ UINT cScans,
-    _Out_opt_ LPBYTE pjBits,
-    _Inout_ LPBITMAPINFO pbmiUser,
+    _Out_writes_bytes_opt_(cjMaxBits) LPBYTE pjBits,
+    _Inout_ LPBITMAPINFO pbmi,
     _In_ UINT iUsage,
     _In_ UINT cjMaxBits,
     _In_ UINT cjMaxInfo)
 {
-    PBITMAPINFO pbmi;
+    PBITMAPINFO pbmiSafe;
     HANDLE hSecure = NULL;
     INT iResult = 0;
     UINT cjAlloc;
@@ -1034,8 +1073,8 @@ NtGdiGetDIBitsInternal(
     cjAlloc = sizeof(BITMAPV5HEADER) + 256 * sizeof(RGBQUAD);
 
     /* Allocate a buffer the bitmapinfo */
-    pbmi = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
-    if (!pbmi)
+    pbmiSafe = ExAllocatePoolWithTag(PagedPool, cjAlloc, 'imBG');
+    if (!pbmiSafe)
     {
         /* Fail */
         return 0;
@@ -1045,8 +1084,8 @@ NtGdiGetDIBitsInternal(
     _SEH2_TRY
     {
         /* Probe and copy the BITMAPINFO */
-        ProbeForRead(pbmiUser, cjMaxInfo, 1);
-        RtlCopyMemory(pbmi, pbmiUser, cjMaxInfo);
+        ProbeForRead(pbmi, cjMaxInfo, 1);
+        RtlCopyMemory(pbmiSafe, pbmi, cjMaxInfo);
     }
     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
@@ -1055,8 +1094,8 @@ NtGdiGetDIBitsInternal(
     _SEH2_END;
 
     /* Check if the header size is large enough */
-    if ((pbmi->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
-        (pbmi->bmiHeader.biSize > cjMaxInfo))
+    if ((pbmiSafe->bmiHeader.biSize < sizeof(BITMAPCOREHEADER)) ||
+        (pbmiSafe->bmiHeader.biSize > cjMaxInfo))
     {
         goto cleanup;
     }
@@ -1078,7 +1117,7 @@ NtGdiGetDIBitsInternal(
                                    iStartScan,
                                    cScans,
                                    pjBits,
-                                   pbmi,
+                                   pbmiSafe,
                                    iUsage,
                                    cjMaxBits,
                                    cjMaxInfo);
@@ -1090,20 +1129,21 @@ NtGdiGetDIBitsInternal(
         _SEH2_TRY
         {
             /* Copy the data back */
-            cjMaxInfo = DIB_BitmapInfoSize(pbmi, (WORD)iUsage);
-            ProbeForWrite(pbmiUser, cjMaxInfo, 1);
-            RtlCopyMemory(pbmiUser, pbmi, cjMaxInfo);
+            cjMaxInfo = min(cjMaxInfo, (UINT)DIB_BitmapInfoSize(pbmiSafe, (WORD)iUsage));
+            ProbeForWrite(pbmi, cjMaxInfo, 1);
+            RtlCopyMemory(pbmi, pbmiSafe, cjMaxInfo);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
             /* Ignore */
+            (VOID)0;
         }
         _SEH2_END;
     }
 
 cleanup:
     if (hSecure) EngUnsecureMem(hSecure);
-    ExFreePoolWithTag(pbmi, 'imBG');
+    ExFreePoolWithTag(pbmiSafe, 'imBG');
 
     return iResult;
 }
@@ -1228,7 +1268,7 @@ NtGdiStretchDIBitsInternal(
     RECTL_vOffsetRect(&rcDst, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
 
     hbmTmp = GreCreateBitmapEx(pbmi->bmiHeader.biWidth,
-                               pbmi->bmiHeader.biHeight,
+                               abs(pbmi->bmiHeader.biHeight),
                                0,
                                BitmapFormat(pbmi->bmiHeader.biBitCount,
                                             pbmi->bmiHeader.biCompression),
@@ -1271,10 +1311,6 @@ NtGdiStretchDIBitsInternal(
                           pdc->pdcattr->crBackgroundClr,
                           pdc->pdcattr->crForegroundClr);
 
-    /* Mask away everything except foreground rop index */
-    dwRop = dwRop & 0x00FF0000;
-    dwRop |= dwRop << 8;
-
     /* Perform the stretch operation */
     bResult = IntEngStretchBlt(&psurfDst->SurfObj,
                                &psurfTmp->SurfObj,
@@ -1287,7 +1323,7 @@ NtGdiStretchDIBitsInternal(
                                NULL,
                                &pdc->eboFill.BrushObject,
                                NULL,
-                               ROP_TO_ROP4(dwRop));
+                               WIN32_ROP3_TO_ENG_ROP4(dwRop));
 
     /* Cleanup */
     DC_vFinishBlit(pdc, NULL);
@@ -1314,6 +1350,7 @@ IntCreateDIBitmap(
     ULONG compression,
     DWORD init,
     LPBYTE bits,
+    ULONG cjMaxBits,
     PBITMAPINFO data,
     DWORD coloruse)
 {
@@ -1357,7 +1394,11 @@ IntCreateDIBitmap(
             /* Undocumented flag which creates a DDB of the format specified by the bitmap info. */
             handle = IntCreateCompatibleBitmap(Dc, width, height, planes, bpp);
             if (!handle)
+            {
+                DPRINT1("IntCreateCompatibleBitmap() failed!\n");
                 return NULL;
+            }
+
             /* The palette must also match the given data */
             Surface = SURFACE_ShareLockSurface(handle);
             ASSERT(Surface);
@@ -1377,7 +1418,7 @@ IntCreateDIBitmap(
     else
     {
         handle = GreCreateBitmap(width,
-                                 height,
+                                 abs(height),
                                  1,
                                  1,
                                  NULL);
@@ -1388,7 +1429,7 @@ IntCreateDIBitmap(
 
     if ((NULL != handle) && (CBM_INIT & init))
     {
-        IntSetDIBits(Dc, handle, 0, height, bits, data, coloruse);
+        IntSetDIBits(Dc, handle, 0, height, bits, cjMaxBits, data, coloruse);
     }
 
     return handle;
@@ -1415,12 +1456,18 @@ NtGdiCreateDIBitmapInternal(
     PBYTE safeBits = NULL;
     HBITMAP hbmResult = NULL;
 
+    if (pjInit == NULL)
+    {
+        fInit &= ~CBM_INIT;
+    }
+
     if(pjInit && (fInit & CBM_INIT))
     {
         if (cjMaxBits == 0) return NULL;
         safeBits = ExAllocatePoolWithTag(PagedPool, cjMaxBits, TAG_DIB);
         if(!safeBits)
         {
+            DPRINT1("Failed to allocate %lu bytes\n", cjMaxBits);
             EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
             return NULL;
         }
@@ -1443,6 +1490,7 @@ NtGdiCreateDIBitmapInternal(
 
     if(!NT_SUCCESS(Status))
     {
+        DPRINT1("Got an exception! pjInit = %p\n", pjInit);
         SetLastNtError(Status);
         goto cleanup;
     }
@@ -1489,6 +1537,7 @@ GreCreateDIBitmapInternal(
         hdcDest = NtGdiCreateCompatibleDC(0);
         if(!hdcDest)
         {
+            DPRINT1("NtGdiCreateCompatibleDC failed\n");
             return NULL;
         }
     }
@@ -1500,6 +1549,7 @@ GreCreateDIBitmapInternal(
     Dc = DC_LockDc(hdcDest);
     if (!Dc)
     {
+        DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return NULL;
     }
@@ -1527,7 +1577,7 @@ GreCreateDIBitmapInternal(
         planes = 0;
         compression = 0;
     }
-    Bmp = IntCreateDIBitmap(Dc, cx, cy, bpp, planes, compression, fInit, pjInit, pbmi, iUsage);
+    Bmp = IntCreateDIBitmap(Dc, cx, cy, planes, bpp, compression, fInit, pjInit, cjMaxBits, pbmi, iUsage);
     DC_UnlockDc(Dc);
 
     if(!hDc)
@@ -1537,6 +1587,56 @@ GreCreateDIBitmapInternal(
     return Bmp;
 }
 
+HBITMAP
+NTAPI
+GreCreateDIBitmapFromPackedDIB(
+    _In_reads_(cjPackedDIB )PVOID pvPackedDIB,
+    _In_ UINT cjPackedDIB,
+    _In_ ULONG uUsage)
+{
+    PBITMAPINFO pbmi;
+    PBYTE pjBits;
+    UINT cjInfo, cjBits;
+    HBITMAP hbm;
+
+    /* We only support BITMAPINFOHEADER, make sure the size is ok */
+    if (cjPackedDIB < sizeof(BITMAPINFOHEADER))
+    {
+        return NULL;
+    }
+
+    /* The packed DIB starts with the BITMAPINFOHEADER */
+    pbmi = pvPackedDIB;
+
+    if (cjPackedDIB < pbmi->bmiHeader.biSize)
+    {
+        return NULL;
+    }
+
+    /* Calculate the info size and make sure the packed DIB is large enough */
+    cjInfo = DIB_BitmapInfoSize(pbmi, uUsage);
+    if (cjPackedDIB <= cjInfo)
+    {
+        return NULL;
+    }
+
+    /* The bitmap bits start after the header */
+    pjBits = (PBYTE)pvPackedDIB + cjInfo;
+    cjBits = cjPackedDIB - cjInfo;
+
+    hbm = GreCreateDIBitmapInternal(NULL,
+                                    pbmi->bmiHeader.biWidth,
+                                    abs(pbmi->bmiHeader.biHeight),
+                                    CBM_INIT | CBM_CREATDIB,
+                                    pjBits,
+                                    pbmi,
+                                    uUsage,
+                                    0,
+                                    cjBits,
+                                    NULL);
+
+    return hbm;
+}
 
 HBITMAP
 APIENTRY
@@ -1652,7 +1752,7 @@ DIB_CreateDIBSection(
 
     // Get storage location for DIB bits.  Only use biSizeImage if it's valid and
     // we're dealing with a compressed bitmap.  Otherwise, use width * height.
-    totalSize = bi->biSizeImage && bi->biCompression != BI_RGB && bi->biCompression != BI_BITFIELDS
+    totalSize = (bi->biSizeImage && (bi->biCompression != BI_RGB) && (bi->biCompression != BI_BITFIELDS))
                 ? bi->biSizeImage : (ULONG)(bm.bmWidthBytes * effHeight);
 
     if (section)
@@ -1674,7 +1774,7 @@ DIB_CreateDIBSection(
         }
 
         mapOffset = offset - (offset % Sbi.AllocationGranularity);
-        mapSize = bi->biSizeImage + (offset - mapOffset);
+        mapSize = totalSize + (offset - mapOffset);
 
         SectionOffset.LowPart  = mapOffset;
         SectionOffset.HighPart = 0;
@@ -1724,7 +1824,7 @@ DIB_CreateDIBSection(
                             BitmapFormat(bi->biBitCount * bi->biPlanes, bi->biCompression),
                             BMF_DONTCACHE | BMF_USERMEM | BMF_NOZEROINIT |
                             ((bi->biHeight < 0) ? BMF_TOPDOWN : 0),
-                            bi->biSizeImage,
+                            totalSize,
                             bm.bmBits,
                             0);
     if (!res)
@@ -1864,13 +1964,17 @@ INT APIENTRY DIB_GetDIBImageBytes(INT  width, INT height, INT depth)
 INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
 {
     unsigned int colors, size, masks = 0;
+    unsigned int colorsize;
+
+    colorsize = (coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) :
+                (coloruse == DIB_PAL_INDICES) ? 0 :
+                sizeof(WORD);
 
     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
     {
         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
-        return sizeof(BITMAPCOREHEADER) + colors *
-               ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
+        return sizeof(BITMAPCOREHEADER) + colors * colorsize;
     }
     else  /* Assume BITMAPINFOHEADER */
     {
@@ -1880,7 +1984,7 @@ INT FASTCALL DIB_BitmapInfoSize(const BITMAPINFO * info, WORD coloruse)
             colors = 1 << info->bmiHeader.biBitCount;
         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
-        return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
+        return size + colors * colorsize;
     }
 }