[RFC PATCH] gdi32: allow passing BITMAPINFO with bmiHeader.biSizeImage == 0 for EMF DC.

Jinoh Kang jinoh.kang.kr at gmail.com
Sun Oct 3 14:04:02 CDT 2021


User-facing APIs should accept biSizeImage == 0, and fix it up accordingly.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51834
Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---


Some more testing is needed, particularly for when biSizeImage is set to a
non-zero _but_ invalid value.


 dlls/gdi32/emfdc.c       | 44 +++++++++++++++++++++++++++++++++-------
 dlls/gdi32/gdi_private.h |  7 +++++++
 2 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/dlls/gdi32/emfdc.c b/dlls/gdi32/emfdc.c
index a1c7eb74fd5..0422d6ac9f5 100644
--- a/dlls/gdi32/emfdc.c
+++ b/dlls/gdi32/emfdc.c
@@ -185,6 +185,32 @@ err:
     return 0;
 }
 
+static UINT get_user_dib_image_size( const BITMAPINFO *info )
+{
+    UINT size;
+
+    if (info->bmiHeader.biCompression != BI_RGB)
+    {
+        /* compressed image -- always trust biSizeImage */
+        return info->bmiHeader.biSizeImage;
+    }
+
+    size = get_dib_image_size( info );
+
+    /* biSizeImage can be zero if biCompression == BI_RGB */
+    if (info->bmiHeader.biSizeImage)
+    {
+        if (info->bmiHeader.biSizeImage < size)
+            TRACE( "biSizeImage (%u) smaller than calculated size (%u)",
+                   info->bmiHeader.biSizeImage,
+                   size );
+        else
+            size = info->bmiHeader.biSizeImage; /* FIXME */
+    }
+
+    return size;
+}
+
 static UINT emfdc_add_handle( struct emf *emf, HGDIOBJ obj )
 {
     UINT index;
@@ -1602,19 +1628,22 @@ BOOL EMFDC_StretchDIBits( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst,
 {
     EMRSTRETCHDIBITS *emr;
     BOOL ret;
-    UINT bmi_size, emr_size;
+    UINT bmi_size, emr_size, img_size;
 
     /* calculate the size of the colour table */
     bmi_size = get_dib_info_size( info, usage );
 
-    emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage;
+    /* obtain the size of the image */
+    img_size = get_user_dib_image_size( info );
+
+    emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + img_size;
     if (!(emr = HeapAlloc(GetProcessHeap(), 0, emr_size ))) return 0;
 
     /* write a bitmap info header (with colours) to the record */
     memcpy( &emr[1], info, bmi_size);
 
     /* write bitmap bits to the record */
-    memcpy ( (BYTE *)&emr[1] + bmi_size, bits, info->bmiHeader.biSizeImage );
+    memcpy ( (BYTE *)&emr[1] + bmi_size, bits, img_size );
 
     /* fill in the EMR header at the front of our piece of memory */
     emr->emr.iType = EMR_STRETCHDIBITS;
@@ -1632,7 +1661,7 @@ BOOL EMFDC_StretchDIBits( DC_ATTR *dc_attr, INT x_dst, INT y_dst, INT width_dst,
     emr->offBmiSrc    = sizeof (EMRSTRETCHDIBITS);
     emr->cbBmiSrc     = bmi_size;
     emr->offBitsSrc   = emr->offBmiSrc + bmi_size;
-    emr->cbBitsSrc    = info->bmiHeader.biSizeImage;
+    emr->cbBitsSrc    = img_size;
 
     emr->cxSrc = width_src;
     emr->cySrc = height_src;
@@ -1655,7 +1684,8 @@ BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD widt
 {
     EMRSETDIBITSTODEVICE *emr;
     DWORD bmiSize = get_dib_info_size( info, usage );
-    DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage;
+    DWORD imgSize = get_user_dib_image_size( info );
+    DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + imgSize;
     BOOL ret;
 
     if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
@@ -1675,12 +1705,12 @@ BOOL EMFDC_SetDIBitsToDevice( DC_ATTR *dc_attr, INT x_dst, INT y_dst, DWORD widt
     emr->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE);
     emr->cbBmiSrc = bmiSize;
     emr->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize;
-    emr->cbBitsSrc = info->bmiHeader.biSizeImage;
+    emr->cbBitsSrc = imgSize;
     emr->iUsageSrc = usage;
     emr->iStartScan = startscan;
     emr->cScans = lines;
     memcpy( (BYTE*)emr + emr->offBmiSrc, info, bmiSize );
-    memcpy( (BYTE*)emr + emr->offBitsSrc, bits, info->bmiHeader.biSizeImage );
+    memcpy( (BYTE*)emr + emr->offBitsSrc, bits, imgSize );
 
     if ((ret = emfdc_record( dc_attr->emf, (EMR*)emr )))
         emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h
index 45bd5431a23..72e9ca165b5 100644
--- a/dlls/gdi32/gdi_private.h
+++ b/dlls/gdi32/gdi_private.h
@@ -24,6 +24,7 @@
 
 #include <stdarg.h>
 #include <limits.h>
+#include <stdlib.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -291,6 +292,12 @@ static inline int get_dib_stride( int width, int bpp )
     return ((width * bpp + 31) >> 3) & ~3;
 }
 
+static inline int get_dib_image_size( const BITMAPINFO *info )
+{
+    return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
+        * abs( info->bmiHeader.biHeight );
+}
+
 /* only for use on sanitized BITMAPINFO structures */
 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
 {
-- 
2.31.1




More information about the wine-devel mailing list