
//+----------------------------------------------------------------------------
//
//	File:
//		convert.cpp
//
//	Contents:
//		This module contains the code to read/write DIB, metafile,
//		placeable metafiles, olepres stream, etc... This module also
//		contains routines for converting from one format to other.
//
//	Classes:
//
//	Functions:
//
//	History:
//		15-Feb-94 alexgo    fixed a bug in loading placeable metafiles
//				    from a storage (incorrect size calculation).
//		25-Jan-94 alexgo    first pass at converting to Cairo-style
//				    memory allocations.
//		01/11/93 - alexgo  - added VDATEHEAP macros to every function
//		12/08/93 - ChrisWe - fixed wPrepareBitmapHeader not to use
//			(LPOLESTR) cast
//		12/07/93 - ChrisWe - make default params to StSetSize explicit
//		12/02/93 - ChrisWe - more formatting; fixed UtHMFToMFStm,
//			32 bit version, which was doing questionable things
//			with the hBits handle;  got rid of the OLESTR
//			uses in favor of (void *) or (BYTE *) as appropriate
//		11/29/93 - ChrisWe - move CONVERT_SOURCEISICON, returned
//			by UtOlePresStmToContentsStm(), to utils.h
//		11/28/93 - ChrisWe - begin file inspection and cleanup
//		06/28/93 - SriniK - created
//
//-----------------------------------------------------------------------------

#include <le2int.h>

#pragma SEG(ole2)

NAME_SEG(convert)
ASSERTDATA

#ifndef _MAC
FARINTERNAL_(HMETAFILE) QD2GDI(HANDLE hBits);
#endif

void UtGetHEMFFromContentsStm(LPSTREAM lpstm, HANDLE * phdata);


/************************   FILE FORMATS   **********************************

Normal Metafile (memory or disk based):

	 ------------ ---------------
	| METAHEADER | Metafile bits |
	 ------------ ---------------
	
Placeable Metafile:

	 --------------------- -----------------
	| PLACEABLEMETAHEADER | Normal metafile |
	 --------------------- -----------------

Memory Based DIB:

	 ------------------ --------------- ----------
	| BITMAPINFOHEADER | RGBQUAD array | DIB bits |
	 ------------------ --------------- ----------
	
DIB file format:

	 ------------------ ------------------
	| BITMAPFILEHEADER | Memory based DIB |
	 ------------------ ------------------
	
Ole10NativeStream Format:	
	
	 -------- ----------------------
	| dwSize | Object's Native data |
	 -------- ----------------------
	
PBrush Native data format:

	 -----------------
	| Dib File format |
	 -----------------
	
MSDraw Native data format:

	 --------------------- ------------- ------------- -----------------
	| mapping mode (WORD) | xExt (WORD) | yExt (WORD) | Normal metafile |
	 --------------------- ------------- ------------- -----------------
	
*****************************************************************************/


FARINTERNAL UtGetHGLOBALFromStm(LPSTREAM lpstream, DWORD dwSize,
		HANDLE FAR* lphPres)
{
	VDATEHEAP();

	HANDLE hBits = NULL;
	void FAR *lpBits = NULL;
	HRESULT error;

	// initialize this for error return cases
	*lphPres = NULL;
	
	// allocate a new handle
	if (!(hBits = GlobalAlloc(GMEM_MOVEABLE, dwSize))
			|| !(lpBits = (BYTE *)GlobalLock(hBits)))
	{
		error = ResultFromScode(E_OUTOFMEMORY);
		goto errRtn;
	}
	
	// read the stream into the allocated memory
	if (error = StRead(lpstream, lpBits, dwSize))
		goto errRtn;
	
	// if we got this far, return new handle
	*lphPres = hBits;

errRtn:
	// unlock the handle, if it was successfully locked
	if (lpBits)
		GlobalUnlock(hBits);

	// free the handle if there was an error
	if ((error != NOERROR) && hBits)
		GlobalFree(hBits);

	return(error);
}


#ifndef _MAC

FARINTERNAL UtGetHDIBFromDIBFileStm(LPSTREAM pstm, HANDLE FAR* lphdata)
{
	VDATEHEAP();

	BITMAPFILEHEADER bfh;
	DWORD dwSize; // the size of the data to read
	HRESULT error;
	
	// read the bitmap file header
	if (error = pstm->Read(&bfh, sizeof(BITMAPFILEHEADER), NULL))
	{
		*lphdata = NULL;
		return(error);
	}
	
	// calculate the size of the DIB to read
	dwSize = bfh.bfSize - sizeof(BITMAPFILEHEADER);

	// read the DIB
	return(UtGetHGLOBALFromStm(pstm, dwSize, lphdata));
}


FARINTERNAL_(HANDLE) UtGetHMFPICT(HMETAFILE hMF, BOOL fDeleteOnError,
		DWORD xExt, DWORD yExt)
{
	VDATEHEAP();

	HANDLE hmfp; // handle to the new METAFILEPICT
	LPMETAFILEPICT lpmfp; // pointer to the new METAFILEPICT

	// if no METAFILE, nothing to do
	if (hMF == NULL)
		return(NULL);
	
	// allocate a new handle
	if (!(hmfp = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT))))
		goto errRtn;

	// lock the handle
	if (!(lpmfp = (LPMETAFILEPICT)GlobalLock(hmfp)))
		goto errRtn;

	// make the METAFILEPICT
	lpmfp->hMF = hMF;
	lpmfp->xExt = (int)xExt;
	lpmfp->yExt = (int)yExt;
	lpmfp->mm = MM_ANISOTROPIC;

	GlobalUnlock(hmfp);
	return(hmfp);
	
errRtn:
	if (hmfp)
		GlobalFree(hmfp);
	
	if (fDeleteOnError)
		DeleteMetaFile(hMF);
	
	return(NULL);
}

#endif // _MAC

//+-------------------------------------------------------------------------
//
//  Function:   UtGetHMFFromMFStm
//
//  Synopsis:
//
//  Effects:
//
//  Arguments:  [lpstream] -- stream containing metafile or PICT
//              [dwSize] -- data size within stream
//              [fConvert] -- FALSE for metafile, TRUE for PICT
//              [lphPres] -- placeholder for output metafile
//
//  Requires:   lpstream positioned at start of data
//
//  Returns:    HRESULT
//
//  Modifies:
//
//  Algorithm:
//
//  History:    29-Apr-94 AlexT     Add comment block, enabled Mac conversion
//
//  Notes:
//
//--------------------------------------------------------------------------

FARINTERNAL UtGetHMFFromMFStm(LPSTREAM lpstream, DWORD dwSize,
		BOOL fConvert, HANDLE FAR* lphPres)
{
#ifdef WIN32
        LEDebugOut((DEB_ITRACE, "%p _IN UtGetHMFFromMFStm (%p, %d, %d, %p)\n",
                NULL, lpstream, dwSize, fConvert, lphPres));

        VDATEHEAP();

        BYTE *pbMFData = NULL;
	HRESULT hrError;
	
	// initialize this in case of error return
	*lphPres = NULL;

        // allocate a global handle for the data (since QD2GDI needs a
        // handle)

        pbMFData = (BYTE *) GlobalAlloc(GMEM_FIXED, dwSize);
        if (NULL == pbMFData)
        {
            hrError = ResultFromScode(E_OUTOFMEMORY);
            goto errRtn;
	}
	
	// read the stream into the bit storage
	
	ULONG cbRead;
	hrError = lpstream->Read(pbMFData, dwSize, &cbRead);
        if (FAILED(hrError))
        {
            return(hrError);
        }
	// hrError = StRead(lpstream, pbMFData, dwSize);

        if (hrError != NOERROR)
        {
            goto errRtn;
        }

        if (fConvert)
        {
            //  It's a Mac PICT
            *lphPres = QD2GDI((HGLOBAL) pbMFData);
        }
        else
        {
            //  It's a Windows metafile
            *lphPres = SetMetaFileBitsEx(dwSize, pbMFData);
        }

        if (*lphPres == NULL)
            hrError = ResultFromScode(E_OUTOFMEMORY);

errRtn:
        if (NULL != pbMFData)
        {
            GlobalFree(pbMFData);
        }

        LEDebugOut((DEB_ITRACE, "%p OUT UtGetHMFFromMFStm ( %lx ) [ %p ]\n",
                    NULL, hrError, *lphPres));

	return(hrError);
#else
	HANDLE hBits; // handle to the new METAFILE
	void FAR* lpBits = NULL;
	HRESULT error;
	
	// initialize this in case of error return
	*lphPres = NULL;

	// allocate a new handle, and lock the bits
	if (!(hBits = GlobalAlloc(GMEM_MOVEABLE, dwSize))
			|| !(lpBits = GlobalLock(hBits)))
	{
		error = ResultFromScode(E_OUTOFMEMORY);
		goto errRtn;
	}
	
	// read the stream into the bit storage
	error = StRead(lpstream, lpBits, dwSize);
	GlobalUnlock(hBits);

	if (error)
		goto errRtn;
	
	if (!fConvert)
		*lphPres = SetMetaFileBits(hBits);
	else
	{
		if (*lphPres = QD2GDI(hBits))
		{
			// Need to free this handle upon success
			GlobalFree(hBits);
			hBits = NULL;
		}
	
	}
	
	if (!*lphPres)
		error = ResultFromScode(E_OUTOFMEMORY);
	
errRtn:
	if (error && hBits)
		GlobalFree(hBits);
	return(error);
#endif // WIN32
}


FARINTERNAL UtGetSizeAndExtentsFromPlaceableMFStm(LPSTREAM pstm,
		DWORD FAR* pdwSize, LONG FAR* plWidth, LONG FAR* plHeight)
{
	VDATEHEAP();

	HRESULT error;
	LARGE_INTEGER large_int; // used to set the seek pointer
	ULARGE_INTEGER ularge_int; // retrieves the new seek position
	LONG xExt; // the x extent of the metafile
	LONG yExt; // the y extent of the metafile
	METAHEADER mfh;
	PLACEABLEMETAHEADER plac_mfh;
	
	// read the placeable metafile header
	if (error = pstm->Read(&plac_mfh, sizeof(plac_mfh), NULL))
		return(error);
	
	// check the magic number in the header
	if (plac_mfh.key != PMF_KEY)
		return ResultFromScode(E_FAIL);

	// remember the seek pointer 	
	LISet32(large_int, 0);
	if (error = pstm->Seek(large_int, STREAM_SEEK_CUR, &ularge_int))
		return(error);

	// read metafile header
	if (error = pstm->Read(&mfh, sizeof(mfh), NULL))
		return(error);
	
	// seek back to the begining of metafile header
	LISet32(large_int,  ularge_int.LowPart);
	if (error = pstm->Seek(large_int, STREAM_SEEK_SET, NULL))
		return(error);
	
	// calculate the extents of the metafile
	xExt = (plac_mfh.bbox.right - plac_mfh.bbox.left);// metafile units
	yExt = (plac_mfh.bbox.bottom - plac_mfh.bbox.top);// metafile units
	
	// REVIEW, why aren't there constants for this?
	xExt = (xExt * 2540) / plac_mfh.inch; // HIMETRIC units
	yExt = (yExt * 2540) / plac_mfh.inch; // HIMETRIC units
	
	if (pdwSize)
	{
#ifdef WIN16
		//this code seems to work OK on Win16
		*pdwSize = 2 * (mfh.mtSize + mfh.mtHeaderSize);
				// REVIEW NT: review METAHEADER
#else	//WIN32
		//mt.Size is the size in words of the metafile.
		//this fixes bug 6739 (static objects can't be copied
		//or loaded from a file).
		*pdwSize = sizeof(WORD) * mfh.mtSize;
#endif	//WIN16
	}

	if (plWidth)
		*plWidth = xExt;
	
	if (plHeight)
		*plHeight = yExt;
	
	return NOERROR;
}


FARINTERNAL UtGetHMFPICTFromPlaceableMFStm(LPSTREAM pstm, HANDLE FAR* lphdata)
{
	VDATEHEAP();

	HRESULT error; // error state so far
	DWORD dwSize; // size of the METAFILE we have to read from the stream
	LONG xExt; // x extent of the METAFILE we have to read from the stream
	LONG yExt; // y extent of the METAFILE we have to read from the stream
	HMETAFILE hMF; // handle to the METAFILE read from the stream

	if (lphdata == NULL)
		return ResultFromScode(E_INVALIDARG);
	
	// initialize this in case of error return
	*lphdata = NULL;

	// get the size of the METAFILE
	if (error = UtGetSizeAndExtentsFromPlaceableMFStm(pstm, &dwSize,
			&xExt, &yExt))
		return(error);		

	// fetch the METAFILE
	if (error = UtGetHMFFromMFStm(pstm, dwSize, FALSE /*fConvert*/,
			(HANDLE FAR *)&hMF))
		return(error);
	
	// convert to a METAFILEPICT
	if (!(*lphdata = UtGetHMFPICT(hMF, TRUE /*fDeleteOnError*/, xExt,
			yExt)))
		return ResultFromScode(E_OUTOFMEMORY);

	return NOERROR;
}



/****************************************************************************/
/*****************		Write routines		*********************/
/****************************************************************************/

#ifndef _MAC


//+----------------------------------------------------------------------------
//
//	Function:
//		wPrepareBitmapHeader, static
//
//	Synopsis:
//		Initializes the content of a BITMAPFILEHEADER
//
//	Arguments:
//		[lpbfh] -- pointer to the BITMAPFILEHEADER to initialize
//		[dwSize] -- the size of the file; obtained by dividing
//			the size of the file by 4 (see win32 documentation.)
//
//	History:
//		12/08/93 - ChrisWe - made static
//
//-----------------------------------------------------------------------------
static INTERNAL_(void) wPrepareBitmapFileHeader(LPBITMAPFILEHEADER lpbfh,
		DWORD dwSize)
{
	VDATEHEAP();

	// NOTE THESE ARE NOT SUPPOSED TO BE UNICODE
	// see win32s documentation
	((char *)(&lpbfh->bfType))[0] = 'B';
	((char *)(&lpbfh->bfType))[1] = 'M';

	lpbfh->bfSize = dwSize + sizeof(BITMAPFILEHEADER);
	lpbfh->bfReserved1 = 0;
	lpbfh->bfReserved2 = 0;
	lpbfh->bfOffBits = 0;
}


FARINTERNAL UtHDIBToDIBFileStm(HANDLE hdata, DWORD dwSize, LPSTREAM pstm)
{
	VDATEHEAP();

	HRESULT	error;
	BITMAPFILEHEADER bfh;
	
	wPrepareBitmapFileHeader(&bfh, dwSize);
	
	if (error = pstm->Write(&bfh, sizeof(bfh), NULL))
		return(error);
	
	return UtHGLOBALtoStm(hdata, dwSize, pstm);
}


FARINTERNAL UtDIBStmToDIBFileStm(LPSTREAM pstmDIB, DWORD dwSize,
		LPSTREAM pstmDIBFile)
{
	VDATEHEAP();

	HRESULT	error;
	BITMAPFILEHEADER bfh;
	ULARGE_INTEGER ularge_int; // indicates how much to copy
	
	wPrepareBitmapFileHeader(&bfh, dwSize);
	
	if (error = pstmDIBFile->Write(&bfh, sizeof(bfh), NULL))
		return(error);
	
	ULISet32(ularge_int, dwSize);
	if ((error = pstmDIB->CopyTo(pstmDIBFile, ularge_int, NULL,
			NULL)) == NOERROR)
		StSetSize(pstmDIBFile, 0, TRUE);
	
	return(error);
}	


// REVIEW, move these to utils.h so that gen.cpp and mf.cpp can use them for
// the same purposes
// REVIEW, add some more comments; is HDIBFILEHDR a windows structure?
struct tagHDIBFILEHDR
{
	DWORD dwCompression;
	DWORD dwWidth;
	DWORD dwHeight;
	DWORD dwSize;
};
typedef struct tagHDIBFILEHDR HDIBFILEHDR;

struct tagOLEPRESSTMHDR
{
	DWORD dwAspect;
	DWORD dwLindex;
	DWORD dwAdvf;
};
typedef struct tagOLEPRESSTMHDR OLEPRESSTMHDR;

FARINTERNAL UtHDIBFileToOlePresStm(HANDLE hdata, LPSTREAM pstm)
{
	VDATEHEAP();

	HRESULT error;
	HDIBFILEHDR hdfh;
	LPBITMAPFILEHEADER lpbfh;
	LPBITMAPINFOHEADER lpbmi;
		
	if (!(lpbfh = (LPBITMAPFILEHEADER)GlobalLock(hdata)))
		return ResultFromScode(E_OUTOFMEMORY);
		
	lpbmi = (LPBITMAPINFOHEADER)(((BYTE *)lpbfh) +
			sizeof(BITMAPFILEHEADER));

	hdfh.dwCompression = 0;
	// REVIEW, these casts are hosed
	UtGetDibExtents(lpbmi, (LPLONG)&hdfh.dwWidth, (LPLONG)&hdfh.dwHeight);
	
	hdfh.dwSize = lpbfh->bfSize - sizeof(BITMAPFILEHEADER);
	
	// write compesssion, Width, Height, size
	if (error = pstm->Write(&hdfh, sizeof(hdfh), 0))
		goto errRtn;
	
	// write the BITMAPINFOHEADER
	// REVIEW, does this size include the data?
	if ((error = pstm->Write(lpbmi, hdfh.dwSize, NULL)) == NOERROR)
		StSetSize(pstm, 0, TRUE);
	
errRtn:	
	GlobalUnlock(hdata);
	return(error);
}

#endif // _MAC



FARINTERNAL UtHMFToMFStm(HANDLE FAR* lphMF, DWORD dwSize, LPSTREAM lpstream)
{
	VDATEHEAP();

	HRESULT error;
	
	// if there's no handle, there's nothing to do
	if (*lphMF == 0)
		return ResultFromScode(OLE_E_BLANK);
	
#ifdef _MAC

	AssertSz(GetHandleSize((Handle)*lphMF) == dwSize,
			"pic hdl size not correct");
	HLock( (HANDLE)*lphMF );

	error = StWrite(lpstream, * (*lphMF), dwSize);
		
	// Eric: We should be unlocking, right?
	HUnlock((HANDLE)(*lphMF));
		
	if (error != NOERROR)
		AssertSz(0, "StWrite failure" );
		
#else

	HANDLE hBits = NULL;
	void *lpBits;

#ifdef WIN32

	// allocate memory to hold the METAFILE bits
	hBits = GlobalAlloc(GPTR, dwSize);
	if (hBits == NULL)
		return ResultFromScode(E_OUTOFMEMORY);

	if (!(lpBits = GlobalLock(hBits)))
		goto errRtn;

	// REVIEW, shouldn't we check the returned size?
	// REVIEW, what should we do about enhanced metafiles?  If we
	// convert and write those out (which have more features that 32 bit
	// apps might use,) then you can't read the same document on a win16
	// machine....
	GetMetaFileBitsEx((HMETAFILE)*lphMF, dwSize, lpBits);

	// write the metafile bits out to the stream
	error = StWrite(lpstream, lpBits, dwSize);

	GlobalUnlock(hBits);

errRtn:
	// free the metafile bits
	GlobalFree(hBits);

#else
	if (!(hBits = GetMetaFileBits(*lphMF)))
	{
		error = ResultFromScode(E_OUTOFMEMORY);
			goto errRtn;
	}

	if (lpBits = GlobalLock(hBits))
	{
		error = StWrite(lpstream, lpBits, dwSize);
		GlobalUnlock(hBits);
	}
	else
		error = ResultFromScode(E_OUTOFMEMORY);

	if (hBits)
		*lphMF = SetMetaFileBits(hBits);
errRtn:

#endif // WIN32
#endif // _MAC

	// set the stream size
	if (error == NOERROR)
		StSetSize(lpstream, 0, TRUE);

	return(error);
}


//+----------------------------------------------------------------------------
//
//	Function:
//		wPreparePlaceableMFHeader, static
//
//	Synopsis:
//		Initializes a PLACEABLEMETAHEADER.
//
//	Arguments:
//		[lpplac_mfh] -- pointer to the PLACEABLEMETAHEADER to initialize
//		[lWidth] -- Width of the metafile
//			REVIEW, in what units?
//			REVIEW, why is this not unsigned?
//		[lHeight] -- Height of the metafile
//			REVIEW, in what units?
//			REVIEW, why is this not unsigned?
//
//	Notes:
//
//	History:
//		12/08/93 - ChrisWe - made static
//
//-----------------------------------------------------------------------------
static INTERNAL_(void) wPreparePlaceableMFHeader(
		PLACEABLEMETAHEADER FAR* lpplac_mfh, LONG lWidth, LONG lHeight)
{
	VDATEHEAP();

	WORD FAR* lpw; // roves over the words included in the checksum

	lpplac_mfh->key	= PMF_KEY;
	lpplac_mfh->hmf	= 0;
	lpplac_mfh->inch = 576;	// REVIEW, where's this magic number from?
	lpplac_mfh->bbox.left = 0;
	lpplac_mfh->bbox.top = 0;
	lpplac_mfh->bbox.right = (int) ((lWidth * lpplac_mfh->inch) / 2540);
			// REVIEW, more magic
	lpplac_mfh->bbox.bottom	= (int) ((lHeight * lpplac_mfh->inch) / 2540);	
			// REVIEW, more magic
	lpplac_mfh->reserved = NULL;
	
	// Compute the checksum of the 10 words that precede the checksum field.
	// It is calculated by XORing zero with those 10 words.
	for(lpplac_mfh->checksum = 0, lpw = (WORD FAR*)lpplac_mfh;
			lpw < (WORD FAR*)&lpplac_mfh->checksum; ++lpw)
		lpplac_mfh->checksum ^= *lpw;
}


FARINTERNAL UtHMFToPlaceableMFStm(HANDLE FAR* lphMF, DWORD dwSize,
		LONG lWidth, LONG lHeight, LPSTREAM pstm)
{
	VDATEHEAP();

	PLACEABLEMETAHEADER plac_mfh;
	HRESULT error;
	
	wPreparePlaceableMFHeader(&plac_mfh, lWidth, lHeight);
	
	// write the placeable header to the stream
	if (error = pstm->Write(&plac_mfh, sizeof(plac_mfh), NULL))
		return(error);
	
	// write the rest of the METAFILE to the stream
	return UtHMFToMFStm(lphMF, dwSize, pstm);	
}


FARINTERNAL UtMFStmToPlaceableMFStm(LPSTREAM pstmMF, DWORD dwSize,
		LONG lWidth, LONG lHeight, LPSTREAM pstmPMF)
{
	VDATEHEAP();

	PLACEABLEMETAHEADER plac_mfh;
	HRESULT error;
	ULARGE_INTEGER ularge_int; // indicates how much data to copy
	
	wPreparePlaceableMFHeader(&plac_mfh, lWidth, lHeight);
	
	// write the placeable header to the stream
	if (error = pstmPMF->Write(&plac_mfh, sizeof(plac_mfh), NULL))
		return(error);

	// copy the METAFILE data from one stream to the other
	ULISet32(ularge_int, dwSize);
	if ((error = pstmMF->CopyTo(pstmPMF, ularge_int, NULL, NULL)) ==
			NOERROR)
		StSetSize(pstmPMF, 0, TRUE);
	
	return(error);
}

//+-------------------------------------------------------------------------
//
//  Function:   UtWriteOlePresStmHeader, private
//
//  Synopsis:   Write the presentation stream header
//
//  Effects:
//
//  Arguments:  [lpstream] -- destination stream
//              [pforetc]  -- FORMATETC for this presentation
//              [dwAdvf]   -- advise flags for the presentation
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Modifies:
//
//  Algorithm:
//
//  History:    11-May-94 AlexT     Added function header, translate to
//                                  ANSI before saving ptd
//
//  Notes:      This function can fail in low memory for presentations with
//              non-NULL ptds (since we allocate memory to do the conversion
//              to the persistent format).  NtIssue #2789
//
//--------------------------------------------------------------------------

FARINTERNAL UtWriteOlePresStmHeader(LPSTREAM lpstream, LPFORMATETC pforetc,
		DWORD dwAdvf)
{
    VDATEHEAP();

    HRESULT error;
    OLEPRESSTMHDR opsh;
	
    // write clip format
    // REVIEW, change name of this function?
    if (error = WriteClipformatStm(lpstream, pforetc->cfFormat))
    	return(error);

    // write target device info
    if (pforetc->ptd)
    {
        DVTDINFO dvtdInfo;
        DVTARGETDEVICE *ptdA;

        error = UtGetDvtd32Info(pforetc->ptd, &dvtdInfo);
        if (FAILED(error))
        {
            return(error);
        }

        ptdA = (DVTARGETDEVICE *) PrivMemAlloc(dvtdInfo.cbConvertSize);
        if (NULL == ptdA)
        {
            return(E_OUTOFMEMORY);
        }

        error = UtConvertDvtd32toDvtd16(pforetc->ptd, &dvtdInfo, ptdA);

        if (SUCCEEDED(error))
        {
            error = StWrite(lpstream, ptdA, ptdA->tdSize);
        }

        PrivMemFree(ptdA);

        if (FAILED(error))
        {
    	    return(error);
        }
    }
    else
    {
    	// if ptd is null then write 4 as size.
    	// REVIEW, what is that the sizeof()?
    	DWORD dwNullPtdLength = 4;

    	if (error = StWrite(lpstream, &dwNullPtdLength, sizeof(DWORD)))
    	    return(error);
    }

    opsh.dwAspect = pforetc->dwAspect;
    opsh.dwLindex = pforetc->lindex;
    opsh.dwAdvf = dwAdvf;
    	
    // write DVASPECT, lindex, advise flags
    return StWrite(lpstream, &opsh, sizeof(opsh));
}

//+-------------------------------------------------------------------------
//
//  Function:   UtReadOlePresStmHeader
//
//  Synopsis:   Reads in a presentation stream header
//
//  Arguments:  [pstm] -- source stream
//              [pforetc] -- FORMATETC to be filled in
//              [pdwAdvf] -- advise flags to be filled in
//              [pfConvert] -- Mac conversion required, to be filled in
//
//  Requires:
//
//  Returns:    HRESULT
//
//  Modifies:
//
//  Algorithm:
//
//  History:    11-May-94 AlexT     Added function header, translate ptd
//                                  from ANSI when loading
//
//  Notes:
//
//--------------------------------------------------------------------------

FARINTERNAL UtReadOlePresStmHeader(LPSTREAM pstm, LPFORMATETC pforetc,
		DWORD FAR* pdwAdvf, BOOL FAR* pfConvert)
{
    VDATEHEAP();

    HRESULT error;
    DWORD dwRead;
    OLEPRESSTMHDR opsh;

    // initialize this for error return cases
    // Check for NULL ptr, as caller may not need this information

    if (pfConvert)
    {
        *pfConvert = FALSE;
    }

    // there's no target device information yet
    pforetc->ptd = NULL;

    // REVIEW, rename this function to indicate its origin?
    error = ReadClipformatStm(pstm, &dwRead);

    if (error == NOERROR)
    	pforetc->cfFormat = (CLIPFORMAT)dwRead;
    else
    {
#ifndef _MAC		
	if (GetScode(error) == OLE_S_MAC_CLIPFORMAT)
	{
	   // check whether the clipformat is "pict"
	   // REVIEW, what's this cuteness?
	   if (dwRead != *((DWORD *)"TCIP"))
	   	return(error);
	
	   if (pfConvert)
	   	*pfConvert = TRUE;
	   else
	   	return ResultFromScode(DV_E_CLIPFORMAT);
	
	   pforetc->cfFormat = CF_METAFILEPICT;
	}	
	else	
#endif		
	    return(error);
    }
	
    // set the proper tymed
    if (pforetc->cfFormat == CF_METAFILEPICT)
    {
	pforetc->tymed = TYMED_MFPICT;
    }
    else if (pforetc->cfFormat == CF_ENHMETAFILE)
    {
	pforetc->tymed = TYMED_ENHMF;
    }
    else if (pforetc->cfFormat == CF_BITMAP)
    {
    	AssertSz(0, "We don't read/save CF_BITMAP anymore");
    	return ResultFromScode(DV_E_CLIPFORMAT);
    }		
    else if (pforetc->cfFormat == NULL)
    {
    	pforetc->tymed = TYMED_NULL;
    }
    else
    {
    	pforetc->tymed = TYMED_HGLOBAL;
    }

    // Read targetdevice info.
    if (error = StRead(pstm, &dwRead, sizeof(dwRead)))
    	return(error);

    // if the tdSize of ptd is non-null and is > 4, then go ahead read the
    // remaining data of the target device info
    if (dwRead > 4)
    {
        DVTARGETDEVICE *ptdA;
        DVTDINFO dvtdInfo;

        ptdA = (DVTARGETDEVICE *) PrivMemAlloc(dwRead);
        if (NULL == ptdA)
        {
    	    return ResultFromScode(E_OUTOFMEMORY);
        }

        ptdA->tdSize = dwRead;
    	error = StRead(pstm, ((BYTE*)ptdA) + sizeof(dwRead),
                       dwRead - sizeof(dwRead));

        if (SUCCEEDED(error))
        {
            error = UtGetDvtd16Info(ptdA, &dvtdInfo);
            if (SUCCEEDED(error))
            {
                pforetc->ptd = (DVTARGETDEVICE *) PubMemAlloc(dvtdInfo.cbConvertSize);
                if (NULL == pforetc->ptd)
                {
    	            error = E_OUTOFMEMORY;
                }
                else
                {
                    error = UtConvertDvtd16toDvtd32(ptdA, &dvtdInfo, pforetc->ptd);
                }
            }
        }

        PrivMemFree(ptdA);

        if (FAILED(error))
        {
    	    goto errRtn;
        }
    }
    else
    	pforetc->ptd = NULL;

    // Read DVASPECT, lindex, advise flags
    if ((error = StRead(pstm, &opsh, sizeof(opsh))) != NOERROR)
    	goto errRtn;

    pforetc->dwAspect = opsh.dwAspect;
    pforetc->lindex = opsh.dwLindex;
    if (pdwAdvf)
    	*pdwAdvf = opsh.dwAdvf;

    return NOERROR;

errRtn:
    if (pforetc->ptd)
    {
        PubMemFree(pforetc->ptd);
	pforetc->ptd = NULL;		
    }

    return(error);
}


FARINTERNAL UtOlePresStmToContentsStm(LPSTORAGE pstg, LPOLESTR lpszPresStm,
		BOOL fDeletePresStm, UINT FAR* puiStatus)
{
	VDATEHEAP();

	LPSTREAM pstmOlePres;
	LPSTREAM pstmContents = NULL;
	HRESULT error;
	FORMATETC foretc;
	HDIBFILEHDR hdfh;
	
	// there's no status yet
	*puiStatus = 0;
	
	if ((error = pstg->OpenStream(lpszPresStm, NULL,
			(STGM_READ | STGM_SHARE_EXCLUSIVE), 0, &pstmOlePres)) !=
			NOERROR)
	{
		// we can't open the source stream
		*puiStatus |= CONVERT_NOSOURCE;
		
		// check whether "CONTENTS" stream exits
		if (pstg->OpenStream(OLE_CONTENTS_STREAM, NULL,
				(STGM_READ | STGM_SHARE_EXCLUSIVE), 0,
				&pstmContents) != NOERROR)
		{
			// we can't open the destination stream either
			// REVIEW, since we can't open the source, who cares?
			// REVIEW, is there a cheaper way to test existence
			// other than opening?
			*puiStatus |= CONVERT_NODESTINATION;
		}
		else
			pstmContents->Release();
		
		return(error);
	}
	
	foretc.ptd = NULL;
	if (error = UtReadOlePresStmHeader(pstmOlePres, &foretc, NULL, NULL))
		goto errRtn;
			
	if (error = pstmOlePres->Read(&hdfh, sizeof(hdfh), 0))
		goto errRtn;
			
	AssertSz(hdfh.dwCompression == 0,
			"Non-zero compression not supported");
	
	if (error = OpenOrCreateStream(pstg, OLE_CONTENTS_STREAM,
			&pstmContents))
	{
		*puiStatus |= CONVERT_NODESTINATION;		
		goto errRtn;
	}
	
	if (foretc.dwAspect == DVASPECT_ICON)
	{
		*puiStatus |= CONVERT_SOURCEISICON;				
		fDeletePresStm = FALSE;
		error = NOERROR;
		goto errRtn;
	}
	
	if (foretc.cfFormat == CF_DIB)
		error = UtDIBStmToDIBFileStm(pstmOlePres, hdfh.dwSize,
				pstmContents);
	else if (foretc.cfFormat == CF_METAFILEPICT)
		error = UtMFStmToPlaceableMFStm(pstmOlePres,
				hdfh.dwSize, hdfh.dwWidth, hdfh.dwHeight,
				pstmContents);
	else
		error = ResultFromScode(DV_E_CLIPFORMAT);
	
errRtn:
	if (pstmOlePres)
		pstmOlePres->Release();
			
	if (pstmContents)
		pstmContents->Release();

	if (foretc.ptd)
		PubMemFree(foretc.ptd);

	if (error == NOERROR)
	{
		if (fDeletePresStm && lpszPresStm)				
			pstg->DestroyElement(lpszPresStm);
	}
	else
	{
		pstg->DestroyElement(OLE_CONTENTS_STREAM);
	}

	return(error);
}	


FARINTERNAL_(HANDLE) UtGetHPRESFromNative(LPSTORAGE pstg, CLIPFORMAT cfFormat,
		BOOL fOle10Native)
{
	VDATEHEAP();

	LPSTREAM pstm;
	HGLOBAL hdata = NULL;
	
	if ((cfFormat != CF_METAFILEPICT) && 
	    (cfFormat != CF_DIB) &&
	    (cfFormat != CF_ENHMETAFILE))
	{
		return(NULL);
	}

	if (fOle10Native)
	{
		DWORD dwSize;

		if (pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
				(STGM_READ | STGM_SHARE_EXCLUSIVE), 0,
				&pstm) != NOERROR)
			return(NULL);
		
		if (pstm->Read(&dwSize, sizeof(DWORD), NULL) == NOERROR)
		{
			// is it PBrush native data?
			if (cfFormat == CF_DIB)
				UtGetHDIBFromDIBFileStm(pstm, &hdata);
			else
			{
				// MSDraw native data or PaintBrush
				//
				UtGetHMFPICTFromMSDrawNativeStm(pstm, dwSize,
						&hdata);
			}
		}
	}
	else
	{
		if (pstg->OpenStream(OLE_CONTENTS_STREAM, NULL,
				(STGM_READ | STGM_SHARE_EXCLUSIVE), 0,
				&pstm) != NOERROR)
			return(NULL);
		
		if (cfFormat == CF_DIB)
		{
			UtGetHDIBFromDIBFileStm(pstm, &hdata);
		}
		else if (cfFormat == CF_METAFILEPICT)
		{
			UtGetHMFPICTFromPlaceableMFStm(pstm, &hdata);
		}
		else
		{
			UtGetHEMFFromContentsStm(pstm, &hdata);
		}
	}
	
	pstm->Release();
	return(hdata);
}


