RESEND: enhmetafile: Read and write support for little-endian EMFs on big-endian machines

Phil Krylov phil at newstar.rinet.ru
Sun Jun 25 03:04:59 CDT 2006


Hi,

This version has no ugly macros and adds read support. Diffed against current
CVS.

ChangeLog:

enhmetafile: Read and write support for little-endian EMFs on big-endian
machines.

Patch:

Index: dlls/gdi/enhmetafile.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmetafile.c,v
retrieving revision 1.22
diff -p -u -r1.22 enhmetafile.c
--- dlls/gdi/enhmetafile.c	21 Jun 2006 10:27:38 -0000	1.22
+++ dlls/gdi/enhmetafile.c	25 Jun 2006 07:21:32 -0000
@@ -43,6 +43,7 @@
 #include "wingdi.h"
 #include "winnls.h"
 #include "winerror.h"
+#include "winternl.h"
 #include "gdi.h"
 #include "gdi_private.h"
 #include "wine/debug.h"
@@ -245,6 +246,289 @@ static inline BOOL is_dib_monochrome( co
     }
 }

+
+#ifdef WORDS_BIGENDIAN
+
+static inline void byteswap_dword(DWORD *ptr)
+{
+    *ptr = RtlUlongByteSwap(*ptr);
+}
+static inline void byteswap_word(WORD *ptr)
+{
+    *ptr = RtlUshortByteSwap(*ptr);
+}
+static inline void byteswap_uint(UINT *ptr)
+{
+    byteswap_dword((DWORD *)ptr);
+}
+static inline void byteswap_float(FLOAT *ptr)
+{
+    byteswap_dword((DWORD *)ptr);
+}
+static inline void byteswap_point(POINT *ptr)
+{
+    byteswap_dword(&ptr->x);
+    byteswap_dword(&ptr->y);
+}
+static inline void byteswap_pointl(POINTL *ptr)
+{
+    byteswap_point((POINT *)ptr);
+}
+static inline void byteswap_sizel(SIZEL *ptr)
+{
+    byteswap_point((POINT *)ptr);
+}
+static inline void byteswap_rectl(RECTL *ptr)
+{
+    byteswap_dword(&ptr->left);
+    byteswap_dword(&ptr->top);
+    byteswap_dword(&ptr->right);
+    byteswap_dword(&ptr->bottom);
+}
+static inline void byteswap_wstr(WCHAR *ptr, int len)
+{
+    int i;
+    for (i = 0; i < len; i++)
+        byteswap_word((WORD *)ptr + i);
+}
+static inline void byteswap_dword_array(DWORD *ptr, int len)
+{
+    int i;
+    for (i = 0; i < len; i++)
+        byteswap_dword(ptr + i);
+}
+static inline void byteswap_wstr_ofs(void *ptr, int ofs, int len)
+{
+    byteswap_wstr((WCHAR *)((char *)ptr + ofs), len);
+}
+static inline void byteswap_dword_array_ofs(void *ptr, int ofs, int len)
+{
+    byteswap_dword_array((DWORD *)((char *)ptr + ofs), len);
+}
+
+void EMF_ByteSwapRecord(ENHMETARECORD *emrSrc, ENHMETARECORD *emrDst,
+                        BOOL bNative)
+{
+    ENHMETARECORD *emrNative = bNative ? emrSrc : emrDst;
+
+    memmove(emrDst, emrSrc,
+            bNative ? emrSrc->nSize : RtlUlongByteSwap(emrSrc->nSize));
+    byteswap_dword(&emrDst->iType);
+    byteswap_dword(&emrDst->nSize);
+    switch (emrNative->iType)
+    {
+        case EMR_HEADER:
+        {
+            ENHMETAHEADER *pemrNative = (ENHMETAHEADER *)emrNative;
+            ENHMETAHEADER *pemrDst = (ENHMETAHEADER *)emrDst;
+
+            byteswap_rectl(&pemrDst->rclBounds);
+            byteswap_rectl(&pemrDst->rclFrame);
+            byteswap_dword(&pemrDst->dSignature);
+            byteswap_dword(&pemrDst->nVersion);
+            byteswap_dword(&pemrDst->nBytes);
+            byteswap_dword(&pemrDst->nRecords);
+            byteswap_word(&pemrDst->nHandles);
+            byteswap_word(&pemrDst->sReserved);
+            byteswap_dword(&pemrDst->nDescription);
+            byteswap_dword(&pemrDst->offDescription);
+            byteswap_dword(&pemrDst->nPalEntries);
+            byteswap_sizel(&pemrDst->szlDevice);
+            byteswap_sizel(&pemrDst->szlMillimeters);
+            byteswap_dword(&pemrDst->cbPixelFormat);
+            byteswap_dword(&pemrDst->offPixelFormat);
+            byteswap_dword(&pemrDst->bOpenGL);
+            byteswap_sizel(&pemrDst->szlMicrometers);
+            byteswap_wstr_ofs(pemrDst, pemrNative->offDescription,
+                              pemrNative->nDescription);
+            break;
+        }
+        case EMR_ABORTPATH:
+        case EMR_BEGINPATH:
+        case EMR_ENDPATH:
+        case EMR_CLOSEFIGURE:
+        case EMR_FLATTENPATH:
+        case EMR_WIDENPATH:
+        case EMR_SETMETARGN:
+        case EMR_SAVEDC:
+        case EMR_REALIZEPALETTE:
+            break;
+        case EMR_SELECTCLIPPATH:
+        case EMR_SETBKMODE:
+        case EMR_SETMAPMODE:
+        case EMR_SETPOLYFILLMODE:
+        case EMR_SETROP2:
+        case EMR_SETSTRETCHBLTMODE:
+        case EMR_SETTEXTALIGN:
+        case EMR_SETICMMODE:
+        case EMR_SETLAYOUT:
+        case EMR_DELETEOBJECT:
+        case EMR_SELECTOBJECT:
+        case EMR_DELETECOLORSPACE:
+        case EMR_SETCOLORSPACE:
+        case EMR_RESTOREDC:
+        case EMR_SELECTPALETTE:
+        case EMR_SETARCDIRECTION:
+        case EMR_SETBKCOLOR:
+        case EMR_SETTEXTCOLOR:
+        case EMR_SETMAPPERFLAGS:
+        case EMR_SETMITERLIMIT:
+        {
+            EMRSETROP2 *pemrDst = (EMRSETROP2 *)emrDst;
+
+            byteswap_dword(&pemrDst->iMode);
+            break;
+        }
+        case EMR_LINETO:
+        case EMR_MOVETOEX:
+        {
+            EMRMOVETOEX *pemrDst = (EMRMOVETOEX *)emrDst;
+
+            byteswap_pointl(&pemrDst->ptl);
+            break;
+        }
+        case EMR_ANGLEARC:
+        {
+            EMRANGLEARC *pemrDst = (EMRANGLEARC *)emrDst;
+
+            byteswap_pointl(&pemrDst->ptlCenter);
+            byteswap_dword(&pemrDst->nRadius);
+            byteswap_float(&pemrDst->eStartAngle);
+            byteswap_float(&pemrDst->eSweepAngle);
+            break;
+        }
+        case EMR_ARC:
+        case EMR_ARCTO:
+        case EMR_CHORD:
+        case EMR_PIE:
+        {
+            EMRARC *pemrDst = (EMRARC *)emrDst;
+
+            byteswap_rectl(&pemrDst->rclBox);
+            byteswap_pointl(&pemrDst->ptlStart);
+            byteswap_pointl(&pemrDst->ptlEnd);
+            break;
+        }
+        case EMR_EXTCREATEFONTINDIRECTW:
+        {
+            EMREXTCREATEFONTINDIRECTW *pemrDst =
(EMREXTCREATEFONTINDIRECTW *)emrDst;
+
+            byteswap_dword(&pemrDst->ihFont);
+            byteswap_dword(&pemrDst->elfw.elfLogFont.lfHeight);
+            byteswap_dword(&pemrDst->elfw.elfLogFont.lfWidth);
+            byteswap_dword(&pemrDst->elfw.elfLogFont.lfEscapement);
+            byteswap_dword(&pemrDst->elfw.elfLogFont.lfOrientation);
+            byteswap_dword(&pemrDst->elfw.elfLogFont.lfWeight);
+            byteswap_wstr(pemrDst->elfw.elfLogFont.lfFaceName, LF_FACESIZE);
+            byteswap_wstr(pemrDst->elfw.elfFullName, LF_FULLFACESIZE);
+            byteswap_wstr(pemrDst->elfw.elfStyle, LF_FACESIZE);
+            break;
+        }
+        case EMR_CREATEPEN:
+        {
+            EMRCREATEPEN *pemrDst = (EMRCREATEPEN *)emrDst;
+
+            byteswap_dword(&pemrDst->ihPen);
+            byteswap_uint(&pemrDst->lopn.lopnStyle);
+            byteswap_point(&pemrDst->lopn.lopnWidth);
+            byteswap_dword(&pemrDst->lopn.lopnColor);
+            break;
+        }
+        case EMR_CREATEBRUSHINDIRECT:
+        {
+            EMRCREATEBRUSHINDIRECT *pemrDst = (EMRCREATEBRUSHINDIRECT *)emrDst;
+
+            byteswap_dword(&pemrDst->ihBrush);
+            byteswap_uint(&pemrDst->lb.lbStyle);
+            byteswap_dword(&pemrDst->lb.lbColor);
+            byteswap_dword(&pemrDst->lb.lbHatch);
+            break;
+        }
+        case EMR_ELLIPSE:
+        case EMR_RECTANGLE:
+        {
+            EMRRECTANGLE *pemrDst = (EMRRECTANGLE *)emrDst;
+
+            byteswap_rectl(&pemrDst->rclBox);
+            break;
+        }
+        case EMR_EXTTEXTOUTW:
+        {
+            EMREXTTEXTOUTW *pemrNative = (EMREXTTEXTOUTW *)emrNative;
+            EMREXTTEXTOUTW *pemrDst = (EMREXTTEXTOUTW *)emrDst;
+
+            byteswap_rectl(&pemrDst->rclBounds);
+            byteswap_dword(&pemrDst->iGraphicsMode);
+            byteswap_float(&pemrDst->exScale);
+            byteswap_float(&pemrDst->eyScale);
+            byteswap_pointl(&pemrDst->emrtext.ptlReference);
+            byteswap_dword(&pemrDst->emrtext.nChars);
+            byteswap_dword(&pemrDst->emrtext.offString);
+            byteswap_dword(&pemrDst->emrtext.fOptions);
+            byteswap_rectl(&pemrDst->emrtext.rcl);
+            byteswap_dword(&pemrDst->emrtext.offDx);
+            byteswap_wstr_ofs(pemrDst, pemrNative->emrtext.offString,
+                              pemrNative->emrtext.nChars);
+            byteswap_dword_array_ofs(pemrDst, pemrNative->emrtext.offDx,
+                                     pemrNative->emrtext.nChars);
+            break;
+        }
+        case EMR_EOF:
+        {
+            EMREOF *pemrNative = (EMREOF *)emrNative;
+            EMREOF *pemrDst = (EMREOF *)emrDst;
+            DWORD nPalLen = pemrNative->nPalEntries * sizeof(PALETTEENTRY);
+
+            byteswap_dword(&pemrDst->nPalEntries);
+            byteswap_dword(&pemrDst->offPalEntries);
+            if (pemrNative->nPalEntries)
+                byteswap_dword_array_ofs(pemrDst,
+                                         pemrNative->offPalEntries + nPalLen,
+                                         1);
+            else
+                byteswap_dword(&pemrDst->nSizeLast);
+            break;
+        }
+        default:
+            FIXME("doesn't know how to byteswap record %s\n",
+                  get_emr_name(emrNative->iType));
+            break;
+    }
+}
+
+ENHMETAHEADER *EMF_ByteSwapEnhMetaFile(ENHMETAHEADER *emh,
+                                       BOOL bNative, BOOL bOnlyHeader)
+{
+    int nBytes = bNative ? emh->nBytes : RtlUlongByteSwap(emh->nBytes);
+    int nRecords;
+    ENHMETAHEADER *emhSwap = HeapAlloc(GetProcessHeap(), 0, nBytes);
+    ENHMETARECORD *pemr = (ENHMETARECORD *)emh;
+    ENHMETARECORD *pemrSwap = (ENHMETARECORD *)emhSwap;
+    int i;
+
+    if (!emhSwap)
+        return NULL;
+
+    memset(emhSwap, 0, nBytes);
+    if (bOnlyHeader)
+        nRecords = 1;
+    else
+        nRecords = bNative ? emh->nRecords : RtlUlongByteSwap(emh->nRecords);
+    for (i = 0; i < nRecords; i++)
+    {
+        int nSize;
+
+        EMF_ByteSwapRecord(pemr, pemrSwap, bNative);
+        nSize = bNative ? pemr->nSize : pemrSwap->nSize;
+        pemrSwap = (ENHMETARECORD *)(((char *)pemrSwap) + nSize);
+        pemr = (ENHMETARECORD *)(((char *)pemr) + nSize);
+    }
+    return emhSwap;
+}
+
+#endif /* WORDS_BIGENDIAN */
+
+
 /****************************************************************************
  *          EMF_Create_HENHMETAFILE
  */
@@ -272,10 +556,14 @@ static BOOL EMF_Delete_HENHMETAFILE( HEN
 							   ENHMETAFILE_MAGIC );
     if(!metaObj) return FALSE;

+#ifdef WORDS_BIGENDIAN
+    HeapFree( GetProcessHeap(), 0, metaObj->emh );
+#else
     if(metaObj->on_disk)
         UnmapViewOfFile( metaObj->emh );
     else
         HeapFree( GetProcessHeap(), 0, metaObj->emh );
+#endif
     return GDI_FreeObject( hmf, metaObj );
 }

@@ -312,6 +600,17 @@ static HENHMETAFILE EMF_GetEnhMetaFile(

     if (!emh) return 0;

+#ifdef WORDS_BIGENDIAN
+    {
+        ENHMETAHEADER *emh_be = EMF_ByteSwapEnhMetaFile(emh, FALSE, FALSE);
+
+        UnmapViewOfFile(emh);
+        emh = emh_be;
+        if (!emh)
+            return 0;
+    }
+#endif
+
     if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE) {
         WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
 	     emh->iType, emh->dSignature);
@@ -328,7 +627,11 @@ static HENHMETAFILE EMF_GetEnhMetaFile(
     return EMF_Create_HENHMETAFILE( emh, TRUE );

 err:
+#ifdef WORDS_BIGENDIAN
+    HeapFree(GetProcessHeap(), 0, emh);
+#else
     UnmapViewOfFile( emh );
+#endif
     return 0;
 }

@@ -466,7 +769,18 @@ UINT WINAPI GetEnhMetaFileDescriptionW(
  */
 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
 {
-    ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
+    ENHMETAHEADER *emh;
+
+#ifdef WORDS_BIGENDIAN
+    /* Different uses of this function are possible, so I added
+     * automatic endianness detection here */
+    if (((ENHMETAHEADER *)buf)->iType && 0xFF000000)
+    {
+        emh = EMF_ByteSwapEnhMetaFile((ENHMETAHEADER *)buf, FALSE, FALSE);
+        return EMF_Create_HENHMETAFILE( emh, FALSE );
+    }
+#endif
+    emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
     memmove(emh, buf, bufsize);
     return EMF_Create_HENHMETAFILE( emh, FALSE );
 }
@@ -2428,6 +2742,28 @@ BOOL WINAPI DeleteEnhMetaFile(HENHMETAFI
     return EMF_Delete_HENHMETAFILE( hmf );
 }

+
+BOOL EMF_WriteEnhMetaFile(HANDLE hFile, ENHMETAHEADER *emr, BOOL bOnlyHeader)
+{
+    DWORD w;
+    int nSize = bOnlyHeader ? emr->nSize : emr->nBytes;
+
+#ifdef WORDS_BIGENDIAN
+    ENHMETAHEADER *emr_le = EMF_ByteSwapEnhMetaFile(emr, TRUE, bOnlyHeader);
+    BOOL result;
+
+    if (!emr_le)
+        return FALSE;
+
+    result = WriteFile(hFile, emr_le, nSize, &w, NULL);
+    HeapFree(GetProcessHeap(), 0, emr_le);
+    return result;
+#else
+    return WriteFile(hFile, emr, nSize, &w, NULL);
+#endif
+}
+
+
 /*****************************************************************************
  *  CopyEnhMetaFileA (GDI32.@)
  *
@@ -2449,10 +2785,9 @@ HENHMETAFILE WINAPI CopyEnhMetaFileA(
 	hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
     } else {
         HANDLE hFile;
-        DWORD w;
         hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0,
 			     NULL, CREATE_ALWAYS, 0, 0);
-	WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
+        EMF_WriteEnhMetaFile( hFile, emrSrc, FALSE );
 	CloseHandle( hFile );
 	/* Reopen file for reading only, so that apps can share
 	   read access to the file while hmf is still valid */
@@ -2489,10 +2824,9 @@ HENHMETAFILE WINAPI CopyEnhMetaFileW(
 	hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
     } else {
         HANDLE hFile;
-        DWORD w;
         hFile = CreateFileW( file, GENERIC_WRITE | GENERIC_READ, 0,
 			     NULL, CREATE_ALWAYS, 0, 0);
-	WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
+        EMF_WriteEnhMetaFile( hFile, emrSrc, FALSE );
 	CloseHandle( hFile );
 	/* Reopen file for reading only, so that apps can share
 	   read access to the file while hmf is still valid */
Index: dlls/gdi/gdi_private.h
===================================================================
RCS file: /home/wine/wine/dlls/gdi/gdi_private.h,v
retrieving revision 1.34
diff -p -u -r1.34 gdi_private.h
--- dlls/gdi/gdi_private.h	23 May 2006 12:47:58 -0000	1.34
+++ dlls/gdi/gdi_private.h	25 Jun 2006 07:21:33 -0000
@@ -359,6 +359,13 @@ extern BOOL DRIVER_GetDriverName( LPCWST

 /* enhmetafile.c */
 extern HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk );
+BOOL EMF_WriteEnhMetaFile(HANDLE hFile, ENHMETAHEADER *emr, BOOL bOnlyHeader);
+#ifdef WORDS_BIGENDIAN
+extern ENHMETAHEADER *EMF_ByteSwapEnhMetaFile(ENHMETAHEADER *emh,
+                                              BOOL bNative, BOOL bOnlyHeader);
+extern void EMF_ByteSwapRecord(ENHMETARECORD *emrSrc, ENHMETARECORD *emrDst,
+                               BOOL bNative);
+#endif

 /* freetype.c */
 extern INT WineEngAddFontResourceEx(LPCWSTR, DWORD, PVOID);
Index: dlls/gdi/enhmfdrv/init.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmfdrv/init.c,v
retrieving revision 1.35
diff -p -u -r1.35 init.c
--- dlls/gdi/enhmfdrv/init.c	23 May 2006 12:48:00 -0000	1.35
+++ dlls/gdi/enhmfdrv/init.c	25 Jun 2006 07:21:33 -0000
@@ -197,8 +197,18 @@ BOOL EMFDRV_WriteRecord( PHYSDEV dev, EM
     physDev->emh->nRecords++;

     if(physDev->hFile) {
+#ifdef WORDS_BIGENDIAN
+        ENHMETARECORD *emr_le = HeapAlloc(GetProcessHeap(), 0, emr->nSize);
+
+        if (!emr_le)
+            return FALSE;
+        EMF_ByteSwapRecord((ENHMETARECORD *)emr, emr_le, TRUE);
+	if (!WriteFile(physDev->hFile, (char *)emr_le, emr->nSize, NULL, NULL))
+	    return FALSE;
+#else
 	if (!WriteFile(physDev->hFile, (char *)emr, emr->nSize, NULL, NULL))
 	    return FALSE;
+#endif
     } else {
         DWORD nEmfSize = HeapSize(GetProcessHeap(), 0, physDev->emh);
         len = physDev->emh->nBytes;
@@ -407,7 +417,7 @@ HDC WINAPI CreateEnhMetaFileW(
             EMFDRV_DeleteDC( dc->physDev );
             return 0;
         }
-        if (!WriteFile( hFile, (LPSTR)physDev->emh, size, NULL, NULL )) {
+        if (!EMF_WriteEnhMetaFile(hFile, physDev->emh, FALSE)) {
             EMFDRV_DeleteDC( dc->physDev );
             return 0;
 	}
@@ -471,8 +481,7 @@ HENHMETAFILE WINAPI CloseEnhMetaFile(HDC
             return 0;
         }

-        if (!WriteFile(physDev->hFile, (LPSTR)physDev->emh,
-                       sizeof(*physDev->emh), NULL, NULL))
+        if (!EMF_WriteEnhMetaFile(physDev->hFile, physDev->emh, TRUE))
         {
             CloseHandle( physDev->hFile );
             EMFDRV_DeleteDC( dc->physDev );
@@ -486,6 +495,16 @@ HENHMETAFILE WINAPI CloseEnhMetaFile(HDC
 	TRACE("view = %p\n", physDev->emh );
         CloseHandle( hMapping );
         CloseHandle( physDev->hFile );
+#ifdef WORDS_BIGENDIAN
+        if (physDev->emh)
+        {
+            ENHMETAHEADER *emh_be = EMF_ByteSwapEnhMetaFile(physDev->emh,
+                                                            FALSE, FALSE);
+
+            UnmapViewOfFile(physDev->emh);
+            physDev->emh = emh_be;
+        }
+#endif
     }

     hmf = EMF_Create_HENHMETAFILE( physDev->emh, (physDev->hFile != 0) );



More information about the wine-patches mailing list