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