[WIN32K]
[reactos.git] / reactos / win32ss / gdi / ntgdi / dibobj.c
index dc42ad6..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,
@@ -1316,6 +1350,7 @@ IntCreateDIBitmap(
     ULONG compression,
     DWORD init,
     LPBYTE bits,
+    ULONG cjMaxBits,
     PBITMAPINFO data,
     DWORD coloruse)
 {
@@ -1359,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);
@@ -1379,7 +1418,7 @@ IntCreateDIBitmap(
     else
     {
         handle = GreCreateBitmap(width,
-                                 height,
+                                 abs(height),
                                  1,
                                  1,
                                  NULL);
@@ -1390,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;
@@ -1417,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;
         }
@@ -1445,6 +1490,7 @@ NtGdiCreateDIBitmapInternal(
 
     if(!NT_SUCCESS(Status))
     {
+        DPRINT1("Got an exception! pjInit = %p\n", pjInit);
         SetLastNtError(Status);
         goto cleanup;
     }
@@ -1491,6 +1537,7 @@ GreCreateDIBitmapInternal(
         hdcDest = NtGdiCreateCompatibleDC(0);
         if(!hdcDest)
         {
+            DPRINT1("NtGdiCreateCompatibleDC failed\n");
             return NULL;
         }
     }
@@ -1502,6 +1549,7 @@ GreCreateDIBitmapInternal(
     Dc = DC_LockDc(hdcDest);
     if (!Dc)
     {
+        DPRINT1("Failed to lock hdcDest %p\n", hdcDest);
         EngSetLastError(ERROR_INVALID_HANDLE);
         return NULL;
     }
@@ -1529,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)
@@ -1539,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
@@ -1866,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 */
     {
@@ -1882,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;
     }
 }