enhmetafile: Create little-endian EMF files on big-endian machines (fixed)

Phil Krylov phil at newstar.rinet.ru
Tue Apr 11 11:03:22 CDT 2006


Hi,

This time without the extraneous font.c patch.

This patch fixes the generation of EMF files (which are little-endian by nature)
on big-endian machines. It is by no means complete - some record types are still
unsupported, and reading of little-endian EMFs on big-endian machines still does
not work - but it works for my app and can be used as a base for future
improvements.

-- Ph.

ChangeLog:

Generate valid EMF files on big-endian machines.

Patch:

Index: dlls/gdi/enhmetafile.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/enhmetafile.c,v
retrieving revision 1.19
diff -p -u -r1.19 enhmetafile.c
--- dlls/gdi/enhmetafile.c	7 Apr 2006 18:31:22 -0000	1.19
+++ dlls/gdi/enhmetafile.c	11 Apr 2006 15:42:05 -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"
@@ -2429,6 +2430,258 @@ BOOL WINAPI DeleteEnhMetaFile(HENHMETAFI
     return EMF_Delete_HENHMETAFILE( hmf );
 }
 
+
+#ifdef WORDS_BIGENDIAN
+#define SWAP_DWORD(n) RtlUlongByteSwap((n))
+#define SWAP_FLOAT(n) (tmp = RtlUlongByteSwap(*(DWORD *)&n), *(FLOAT *)&tmp)
+#define SWAP_WORD(n) RtlUshortByteSwap((n))
+#define SWAP_POINTL(p) (POINTL){ SWAP_DWORD((p).x), SWAP_DWORD((p).y) }
+#define SWAP_POINT(p) (POINT){ SWAP_DWORD((p).x), SWAP_DWORD((p).y) }
+#define SWAP_RECTL(r) (RECTL){ SWAP_DWORD((r).left), SWAP_DWORD((r).top), \
+                               SWAP_DWORD((r).right), SWAP_DWORD((r).bottom) }
+#define SWAP_SIZEL(s) (SIZEL){ SWAP_DWORD((s).cx), SWAP_DWORD((s).cy) }
+#define SWAP_MEMBER(t, f) (pemrDst->f = SWAP_##t(pemrSrc->f))
+#define SWAP_MEMBER_WSTR(s, l) \
+        for (i = 0; i < (l); i++) \
+            SWAP_MEMBER(WORD, s[i]);
+#define SWAP_OFS_DWORDARRAY(offset, length) \
+        for (i = 0; i < length; i++) \
+            ((DWORD *)(((char *)pemrDst) + offset))[i] = SWAP_DWORD(((DWORD *)(((char *)pemrSrc) + offset))[i]);
+#define SWAP_OFS_WCHARARRAY(offset, length) \
+        for (i = 0; i < length; i++) \
+            ((WCHAR *)(((char *)pemrDst) + offset))[i] = SWAP_WORD(((WCHAR *)(((char *)pemrSrc) + offset))[i]);
+
+void EMF_ByteSwapRecord(ENHMETARECORD *emrSrc, ENHMETARECORD *emrDst)
+{
+    DWORD tmp;
+    int i;
+    
+    emrDst->iType = SWAP_DWORD(emrSrc->iType);
+    emrDst->nSize = SWAP_DWORD(emrSrc->nSize);
+    switch (emrSrc->iType)
+    {
+        case EMR_HEADER:
+        {
+            ENHMETAHEADER *pemrSrc = (ENHMETAHEADER *)emrSrc;
+            ENHMETAHEADER *pemrDst = (ENHMETAHEADER *)emrDst;
+
+            SWAP_MEMBER(RECTL, rclBounds);
+            SWAP_MEMBER(RECTL, rclFrame);
+            SWAP_MEMBER(DWORD, dSignature);
+            SWAP_MEMBER(DWORD, nVersion);
+            SWAP_MEMBER(DWORD, nBytes);
+            SWAP_MEMBER(DWORD, nRecords);
+            SWAP_MEMBER(WORD, nHandles);
+            SWAP_MEMBER(WORD, sReserved);
+            SWAP_MEMBER(DWORD, nDescription);
+            SWAP_MEMBER(DWORD, offDescription);
+            SWAP_MEMBER(DWORD, nPalEntries);
+            SWAP_MEMBER(SIZEL, szlDevice);
+            SWAP_MEMBER(SIZEL, szlMillimeters);
+            SWAP_MEMBER(DWORD, cbPixelFormat);
+            SWAP_MEMBER(DWORD, offPixelFormat);
+            SWAP_MEMBER(DWORD, bOpenGL);
+            SWAP_MEMBER(SIZEL, szlMicrometers);
+            SWAP_OFS_WCHARARRAY(pemrSrc->offDescription, pemrSrc->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 *pemrSrc = (EMRSETROP2 *)emrSrc;
+            EMRSETROP2 *pemrDst = (EMRSETROP2 *)emrDst;
+
+            SWAP_MEMBER(DWORD, iMode);
+            break;
+        }
+        case EMR_LINETO:
+        case EMR_MOVETOEX:
+        {
+            EMRMOVETOEX *pemrSrc = (EMRMOVETOEX *)emrSrc;
+            EMRMOVETOEX *pemrDst = (EMRMOVETOEX *)emrDst;
+
+            SWAP_MEMBER(POINTL, ptl);
+            break;
+        }
+        case EMR_ANGLEARC:
+        {
+            EMRANGLEARC *pemrSrc = (EMRANGLEARC *)emrSrc;
+            EMRANGLEARC *pemrDst = (EMRANGLEARC *)emrDst;
+
+            SWAP_MEMBER(POINTL, ptlCenter);
+            SWAP_MEMBER(DWORD, nRadius);
+            SWAP_MEMBER(FLOAT, eStartAngle);
+            SWAP_MEMBER(FLOAT, eSweepAngle);
+            break;
+        }
+        case EMR_ARC:
+        case EMR_ARCTO:
+        case EMR_CHORD:
+        case EMR_PIE:
+        {
+            EMRARC *pemrSrc = (EMRARC *)emrSrc;
+            EMRARC *pemrDst = (EMRARC *)emrDst;
+
+            SWAP_MEMBER(RECTL, rclBox);
+            SWAP_MEMBER(POINTL, ptlStart);
+            SWAP_MEMBER(POINTL, ptlEnd);
+            break;
+        }
+        case EMR_EXTCREATEFONTINDIRECTW:
+        {
+            EMREXTCREATEFONTINDIRECTW *pemrSrc = (EMREXTCREATEFONTINDIRECTW *)emrSrc;
+            EMREXTCREATEFONTINDIRECTW *pemrDst = (EMREXTCREATEFONTINDIRECTW *)emrDst;
+
+            SWAP_MEMBER(DWORD, ihFont);
+            SWAP_MEMBER(DWORD, elfw.elfLogFont.lfHeight);
+            SWAP_MEMBER(DWORD, elfw.elfLogFont.lfWidth);
+            SWAP_MEMBER(DWORD, elfw.elfLogFont.lfEscapement);
+            SWAP_MEMBER(DWORD, elfw.elfLogFont.lfOrientation);
+            SWAP_MEMBER(DWORD, elfw.elfLogFont.lfWeight);
+            memmove(&pemrDst->elfw.elfLogFont.lfItalic,
+                    &pemrSrc->elfw.elfLogFont.lfItalic, 8);
+            SWAP_MEMBER_WSTR(elfw.elfLogFont.lfFaceName, LF_FACESIZE);
+            SWAP_MEMBER_WSTR(elfw.elfFullName, LF_FULLFACESIZE);
+            SWAP_MEMBER_WSTR(elfw.elfStyle, LF_FACESIZE);
+            break;
+        }
+        case EMR_CREATEPEN:
+        {
+            EMRCREATEPEN *pemrSrc = (EMRCREATEPEN *)emrSrc;
+            EMRCREATEPEN *pemrDst = (EMRCREATEPEN *)emrDst;
+
+            SWAP_MEMBER(DWORD, ihPen);
+            SWAP_MEMBER(DWORD, lopn.lopnStyle);
+            SWAP_MEMBER(POINT, lopn.lopnWidth);
+            SWAP_MEMBER(DWORD, lopn.lopnColor);
+            break;
+        }
+        case EMR_CREATEBRUSHINDIRECT:
+        {
+            EMRCREATEBRUSHINDIRECT *pemrSrc = (EMRCREATEBRUSHINDIRECT *)emrSrc;
+            EMRCREATEBRUSHINDIRECT *pemrDst = (EMRCREATEBRUSHINDIRECT *)emrDst;
+
+            SWAP_MEMBER(DWORD, ihBrush);
+            SWAP_MEMBER(DWORD, lb.lbStyle);
+            SWAP_MEMBER(DWORD, lb.lbColor);
+            SWAP_MEMBER(DWORD, lb.lbHatch);
+            break;
+        }
+        case EMR_ELLIPSE:
+        case EMR_RECTANGLE:
+        {
+            EMRRECTANGLE *pemrSrc = (EMRRECTANGLE *)emrSrc;
+            EMRRECTANGLE *pemrDst = (EMRRECTANGLE *)emrDst;
+
+            SWAP_MEMBER(RECTL, rclBox);
+            break;
+        }
+        case EMR_EXTTEXTOUTW:
+        {
+            EMREXTTEXTOUTW *pemrSrc = (EMREXTTEXTOUTW *)emrSrc;
+            EMREXTTEXTOUTW *pemrDst = (EMREXTTEXTOUTW *)emrDst;
+
+            SWAP_MEMBER(RECTL, rclBounds);
+            SWAP_MEMBER(DWORD, iGraphicsMode);
+            SWAP_MEMBER(FLOAT, exScale);
+            SWAP_MEMBER(FLOAT, eyScale);
+            SWAP_MEMBER(POINTL, emrtext.ptlReference);
+            SWAP_MEMBER(DWORD, emrtext.nChars);
+            SWAP_MEMBER(DWORD, emrtext.offString);
+            SWAP_MEMBER(DWORD, emrtext.fOptions);
+            SWAP_MEMBER(RECTL, emrtext.rcl);
+            SWAP_MEMBER(DWORD, emrtext.offDx);
+            SWAP_OFS_WCHARARRAY(pemrSrc->emrtext.offString, pemrSrc->emrtext.nChars);
+            SWAP_OFS_DWORDARRAY(pemrSrc->emrtext.offDx, pemrSrc->emrtext.nChars);
+            break;
+        }
+        case EMR_EOF:
+        {
+            EMREOF *pemrSrc = (EMREOF *)emrSrc;
+            EMREOF *pemrDst = (EMREOF *)emrDst;
+            DWORD nPalLen = pemrSrc->nPalEntries * sizeof(PALETTEENTRY);
+
+            SWAP_MEMBER(DWORD, nPalEntries);
+            SWAP_MEMBER(DWORD, offPalEntries);
+            if (pemrSrc->nPalEntries)
+            {
+                memmove(((char *)pemrDst) + pemrSrc->offPalEntries,
+                        ((char *)pemrSrc) + pemrSrc->offPalEntries,
+                        nPalLen);
+                SWAP_OFS_DWORDARRAY(pemrSrc->offPalEntries + nPalLen, 1);
+            }
+            else
+            {
+                SWAP_MEMBER(DWORD, nSizeLast);
+            }
+            break;
+        }
+        default:
+            FIXME("doesn't know how to byteswap record %s\n", get_emr_name(emrSrc->iType));
+            memmove(&emrDst->dParm, &emrSrc->dParm, emrSrc->nSize - sizeof(EMR));
+            break;
+    }
+}
+#endif
+
+BOOL EMF_WriteEnhMetaFile(HANDLE hFile, ENHMETAHEADER *emr, BOOL only_header)
+{
+    DWORD w;
+#ifdef WORDS_BIGENDIAN
+    ENHMETAHEADER *emr_le = HeapAlloc(GetProcessHeap(), 0, emr->nBytes);
+    ENHMETARECORD *pemr = (ENHMETARECORD *)emr;
+    ENHMETARECORD *pemr_le = (ENHMETARECORD *)emr_le;
+    BOOL result;
+    int i;
+
+    if (!emr_le)
+        return FALSE;
+
+    memset(emr_le, 0, emr->nBytes);
+    
+    for (i = 0; i < only_header ? 1 : emr->nRecords; i++)
+    {
+        EMF_ByteSwapRecord(pemr, pemr_le);
+        pemr_le = (ENHMETARECORD *)(((char *)pemr_le) + pemr->nSize);
+        pemr = (ENHMETARECORD *)(((char *)pemr) + pemr->nSize);
+    }
+    result = WriteFile(hFile, emr_le, only_header ? emr->nSize : emr->nBytes, &w, NULL);
+    HeapFree(GetProcessHeap(), 0, emr_le);
+    return result;
+#else
+    return WriteFile(hFile, emr, only_header ? emr->nSize : emr->nBytes, &w, NULL);
+#endif
+}
+
+
 /*****************************************************************************
  *  CopyEnhMetaFileA (GDI32.@)
  *
@@ -2450,10 +2703,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 */
@@ -2490,10 +2742,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.31
diff -p -u -r1.31 gdi_private.h
--- dlls/gdi/gdi_private.h	3 Jan 2006 12:43:52 -0000	1.31
+++ dlls/gdi/gdi_private.h	11 Apr 2006 15:42:06 -0000
@@ -359,6 +359,10 @@ 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 only_header);
+#ifdef WORDS_BIGENDIAN
+extern void EMF_ByteSwapRecord(ENHMETARECORD *emrSrc, ENHMETARECORD *emrDst);
+#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.34
diff -p -u -r1.34 init.c
--- dlls/gdi/enhmfdrv/init.c	25 Jan 2006 12:24:03 -0000	1.34
+++ dlls/gdi/enhmfdrv/init.c	11 Apr 2006 15:42:06 -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);
+	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 );



More information about the wine-patches mailing list