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