Windows2003-3790/windows/advcore/gdiplus/engine/gpmf3216/metafile.cpp
2020-09-30 16:53:55 +02:00

435 lines
13 KiB
C++

/******************************Module*Header*******************************\
* Module Name: metafile.cxx
*
* Includes enhanced metafile API functions.
*
* Created: 17-July-1991 10:10:36
* Author: Hock San Lee [hockl]
*
* Copyright (c) 1991-1999 Microsoft Corporation
\**************************************************************************/
#define NO_STRICT
#define _GDI32_
#define WMF_KEY 0x9ac6cdd7l
extern "C" {
#if defined(_GDIPLUS_)
#include <gpprefix.h>
#endif
#include <string.h>
#include <stdio.h>
#include <nt.h>
#include <ntrtl.h> // defines but doesn't use ASSERT and ASSERTMSG
#undef ASSERT
#undef ASSERTMSG
#include <nturtl.h>
#include <stddef.h>
#include <windows.h> // GDI function declarations.
#include <winspool.h>
#include "..\runtime\debug.h"
#include "mf3216Debug.h"
#define ERROR_ASSERT(cond, msg) ASSERTMSG((cond), (msg))
//#include "nlsconv.h" // UNICODE helpers
//#include "firewall.h"
#define __CPLUSPLUS
#include <winspool.h>
#include <w32gdip.h>
#include "ntgdistr.h"
#include "winddi.h"
#include "hmgshare.h"
#include "icm.h"
#include "local.h" // Local object support.
#include "gdiicm.h"
#include "metadef.h" // Metafile record type constants.
#include "metarec.h"
#include "mf16.h"
#include "ntgdi.h"
#include "glsup.h"
#include "mf3216.h"
#include <GdiplusEnums.h>
}
#undef WARNING
#define WARNING(msg) WARNING1(msg)
#include "rectl.hxx"
#include "mfdc.hxx" // Metafile DC declarations.
#define USE(x) (x)
#include "mfrec.hxx" // Metafile record class declarations.
#undef USE
#undef WARNING
#define WARNING SAVE_WARNING
#include "Metafile.hpp"
DWORD GetDWordCheckSum(UINT cbData, PDWORD pdwData);
#define DbgPrint printf
static inline void PvmsoFromW(void *pv, WORD w)
{ ((BYTE*)pv)[0] = BYTE(w); ((BYTE*)pv)[1] = BYTE(w >> 8); }
static inline void PvmsoFromU(void *pv, ULONG u)
{ ((BYTE*)pv)[0] = BYTE(u);
((BYTE*)pv)[1] = BYTE(u >> 8);
((BYTE*)pv)[2] = BYTE(u >> 16);
((BYTE*)pv)[3] = BYTE(u >> 24); }
#ifdef DBG
static BOOL g_outputEMF = FALSE;
#endif
/******************************Public*Routine******************************\
* GetWordCheckSum(UINT cbData, PWORD pwData)
*
* Adds cbData/2 number of words pointed to by pwData to provide an
* additive checksum. If the checksum is valid the sum of all the WORDs
* should be zero.
*
\**************************************************************************/
static DWORD GetDWordCheckSum(UINT cbData, PDWORD pdwData)
{
DWORD dwCheckSum = 0;
UINT cdwData = cbData / sizeof(DWORD);
ASSERTGDI(!(cbData%sizeof(DWORD)), "GetDWordCheckSum data not DWORD multiple");
ASSERTGDI(!((ULONG_PTR)pdwData%sizeof(DWORD)), "GetDWordCheckSum data not DWORD aligned");
while (cdwData--)
dwCheckSum += *pdwData++;
return(dwCheckSum);
}
/******************************Public*Routine******************************\
* UINT APIENTRY GetWinMetaFileBits(
* HENHMETAFILE hemf,
* UINT nSize,
* LPBYTE lpData
* INT iMapMode,
* HDC hdcRef)
*
* The GetWinMetaFileBits function returns the metafile records of the
* specified enhanced metafile in the Windows 3.0 format and copies
* them into the buffer specified.
*
* Parameter Description
* hemf Identifies the metafile.
* nSize Specifies the size of the buffer reserved for the data. Only this
* many bytes will be written.
* lpData Points to the buffer to receive the metafile data. If this
* pointer is NULL, the function returns the size necessary to hold
* the data.
* iMapMode the desired mapping mode of the metafile contents to be returned
* hdcRef defines the units of the metafile to be returned
*
* Return Value
* The return value is the size of the metafile data in bytes. If an error
* occurs, 0 is returned.
*
* Comments
* The handle used as the hemf parameter does NOT become invalid when the
* GetWinMetaFileBits function returns.
*
* History:
* Thu Apr 8 14:22:23 1993 -by- Hock San Lee [hockl]
* Rewrote it.
* 02-Jan-1992 -by- John Colleran [johnc]
* Wrote it.
\**************************************************************************/
UINT GdipGetWinMetaFileBitsEx
(
HENHMETAFILE hemf,
UINT cbData16,
LPBYTE pData16,
INT iMapMode,
INT eFlags
)
{
BOOL bEmbedEmf = ((eFlags & EmfToWmfBitsFlagsEmbedEmf) == EmfToWmfBitsFlagsEmbedEmf);
BOOL bXorPass = !((eFlags & EmfToWmfBitsFlagsNoXORClip) == EmfToWmfBitsFlagsNoXORClip);
UINT fConverter = 0;
if (bEmbedEmf)
{
fConverter |= MF3216_INCLUDE_WIN32MF;
}
if (bXorPass)
{
fConverter |= GPMF3216_INCLUDE_XORPATH;
}
PEMRGDICOMMENT_WINDOWS_METAFILE pemrWinMF;
UINT uiHeaderSize ;
// Always go through Cleanup to return...
UINT returnVal = 0 ; // Pessimistic Case
PENHMETAHEADER pmfh = NULL;
PBYTE pemfb = NULL;
PUTS("GetWinMetaFileBits\n");
// Validate mapmode.
if ((iMapMode < MM_MIN) ||
(iMapMode > MM_MAX) ||
GetObjectTypeInternal(hemf) != OBJ_ENHMETAFILE)
{
ERROR_ASSERT(FALSE, "GetWinMetaFileBits: Bad mapmode");
return 0;
}
if(hemf == (HENHMETAFILE) 0 )
{
ERROR_ASSERT(FALSE, "GetWinMetaFileBits: Bad HEMF");
return 0;
}
// Validate the metafile handle.
// GillesK:
// We cannot access the MF object from the handle given, but all we need
// is the PENHMETAHEADER, so get it
uiHeaderSize = GetEnhMetaFileHeader(hemf, // handle to enhanced metafile
0, // size of buffer
NULL); // data buffer
// We have the size of the header that we need, so Allocate the header....
// We must make sure to free it after we are done....
pmfh = (PENHMETAHEADER)GlobalAlloc(GMEM_FIXED,uiHeaderSize);
if(pmfh == NULL)
{
goto Cleanup ;
}
uiHeaderSize = GetEnhMetaFileHeader(hemf, // handle to enhanced metafile
uiHeaderSize, // size of buffer
pmfh); // data buffer
ERROR_ASSERT(pmfh->iType == EMR_HEADER, "GetWinMetaFileBits: invalid data");
// ASSERTGDI(pmf->pmrmf->iType == EMR_HEADER, "GetWinMetaFileBits: invalid data");
#ifndef DO_NOT_USE_EMBEDDED_WINDOWS_METAFILE
// See if the this was originally an old style metafile and if it has
// an encapsulated original
pemrWinMF = (PEMRGDICOMMENT_WINDOWS_METAFILE)
((PBYTE) pmfh + ((PENHMETAHEADER) pmfh)->nSize);
if (((PMRGDICOMMENT) pemrWinMF)->bIsWindowsMetaFile())
{
// Make sure that this is what we want and verify checksum
if (iMapMode != MM_ANISOTROPIC)
{
PUTS("GetWinMetaFileBits: Requested and embedded metafile mapmodes mismatch\n");
}
else if ((pemrWinMF->nVersion != METAVERSION300 &&
pemrWinMF->nVersion != METAVERSION100)
|| pemrWinMF->fFlags != 0)
{
// In this release, we can only handle the given metafile
// versions. If we return a version that we don't recognize,
// the app will not be able to play that metafile later on!
//VERIFYGDI(FALSE, "GetWinMetaFileBits: Unrecognized Windows metafile\n");
}
else if (GetDWordCheckSum((UINT) pmfh->nBytes, (PDWORD) pmfh))
{
PUTS("GetWinMetaFileBits: Metafile has been modified\n");
}
else
{
PUTS("GetWinMetaFileBits: Returning embedded Windows metafile\n");
if (pData16)
{
if (cbData16 < pemrWinMF->cbWinMetaFile)
{
ERROR_ASSERT(FALSE, "GetWinMetaFileBits: insufficient buffer");
//GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
goto Cleanup ;
}
RtlCopyMemory(pData16,
(PBYTE) &pemrWinMF[1],
pemrWinMF->cbWinMetaFile);
}
returnVal = pemrWinMF->cbWinMetaFile ;
goto Cleanup ;
}
// Either the enhanced metafile containing an embedded Windows
// metafile has been modified or the embedded Windows metafile
// is not what we want. Since the original format is Windows
// format, we will not embed the enhanced metafile in the
// returned Windows metafile.
PUTS("GetWinMetaFileBits: Skipping embedded windows metafile\n");
fConverter &= ~MF3216_INCLUDE_WIN32MF;
}
#endif // DO_NOT_USE_EMBEDDED_WINDOWS_METAFILE
// Tell the converter to emit the Enhanced metafile as a comment only if
// this metafile is not previously a Windows metafile
if (fConverter & MF3216_INCLUDE_WIN32MF)
{
PUTS("GetWinMetaFileBits: Embedding enhanced metafile\n");
}
else
{
PUTS("GetWinMetaFileBits: No embedding of enhanced metafile\n");
}
uiHeaderSize = GetEnhMetaFileBits(hemf, 0, NULL);
// Allocate the memory to receive the enhance MetaFile
pemfb = (PBYTE) GlobalAlloc(GMEM_FIXED, uiHeaderSize);
if( pemfb == NULL )
{
goto Cleanup;
}
uiHeaderSize = GetEnhMetaFileBits(hemf, uiHeaderSize, pemfb);
#if DBG
// This in only here for debugging... Save the initial EMF file to be
// able to compare later
// We need the ASCII version for it to work with Win98
if (g_outputEMF)
{
::DeleteEnhMetaFile(::CopyEnhMetaFileA(hemf, "C:\\emf.emf" ));
}
#endif
returnVal = (GdipConvertEmfToWmf((PBYTE) pemfb, cbData16, pData16,
iMapMode, NULL,
fConverter));
if(!returnVal && bXorPass)
{
// If we fail then call without the XOR PASS
returnVal = (GdipConvertEmfToWmf((PBYTE) pemfb, cbData16, pData16,
iMapMode, NULL,
fConverter & ~GPMF3216_INCLUDE_XORPATH));
#if DBG
if( !returnVal )
{
// The Win32API version needs an hdcRef, get the screen DC and
// do it
HDC newhdc = ::GetDC(NULL);
// If we fail again then go back to Windows
ASSERT(::GetWinMetaFileBits(hemf, cbData16, pData16,
iMapMode, newhdc) == 0);
::ReleaseDC(NULL, newhdc);
}
#endif
}
Cleanup:
if(pmfh != NULL)
{
GlobalFree(pmfh);
}
if(pemfb != NULL)
{
GlobalFree(pemfb);
}
return returnVal;
}
extern "C"
UINT ConvertEmfToPlaceableWmf
(
HENHMETAFILE hemf,
UINT cbData16,
LPBYTE pData16,
INT iMapMode,
INT eFlags
)
{
UINT uiRet ;
ENHMETAHEADER l_emetaHeader ;
BOOL placeable = (eFlags & EmfToWmfBitsFlagsIncludePlaceable) == EmfToWmfBitsFlagsIncludePlaceable;
// Call the GdipGetWinMetaFileBits
// And add the header information afterwards
// If we have a buffer then leave room for the header
uiRet = GdipGetWinMetaFileBitsEx(hemf,
cbData16,
pData16?pData16+(placeable?22:0):pData16,
iMapMode,
eFlags);
// If the client only wants the size of the buffer, then we return the size
// of the buffer plus the size of the header
if(uiRet != 0 && placeable)
{
// If the previous call succeeded then we will append the size of the
// header to the return value
uiRet += 22;
if(pData16 != NULL)
{
BYTE *rgb = pData16;
PvmsoFromU(rgb , WMF_KEY);
PvmsoFromW(rgb+ 4, 0);
PvmsoFromU(rgb+16, 0);
if(GetEnhMetaFileHeader(hemf, sizeof(l_emetaHeader), &l_emetaHeader))
{
FLOAT pp01mm = ((((FLOAT)l_emetaHeader.szlDevice.cx)/l_emetaHeader.szlMillimeters.cx/100.0f +
(FLOAT)l_emetaHeader.szlDevice.cy)/l_emetaHeader.szlMillimeters.cy/100.0f)/2.0f;
PvmsoFromW(rgb+ 6, SHORT((FLOAT)l_emetaHeader.rclFrame.left*pp01mm));
PvmsoFromW(rgb+ 8, SHORT((FLOAT)l_emetaHeader.rclFrame.top*pp01mm));
PvmsoFromW(rgb+10, SHORT((FLOAT)l_emetaHeader.rclFrame.right*pp01mm));
PvmsoFromW(rgb+12, SHORT((FLOAT)l_emetaHeader.rclFrame.bottom*pp01mm));
PvmsoFromW(rgb+14, SHORT(pp01mm*2540.0f));
}
else
{
// If we cant get the information from the EMF then default
PvmsoFromW(rgb+ 6, SHORT(0));
PvmsoFromW(rgb+ 8, SHORT(0));
PvmsoFromW(rgb+10, SHORT(2000));
PvmsoFromW(rgb+12, SHORT(2000));
PvmsoFromW(rgb+14, 96);
}
/* Checksum. This works on any byte order machine because the data is swapped
consistently. */
USHORT *pu = (USHORT*)rgb;
USHORT u = 0;
/* The checksum is even parity. */
while (pu < (USHORT*)(rgb+20))
u ^= *pu++;
*pu = u;
}
}
return uiRet ;
}