/*************************************************************************
**
**    OLE 2 Standard Utilities
**
**    olestd.c
**
**    This file contains utilities that are useful for dealing with
**    target devices.
**
**    (c) Copyright Microsoft Corp. 1992-1996 All Rights Reserved
**
*************************************************************************/

#define STRICT  1
#include "olestd.h"
#ifndef WIN32
#include <print.h>
#endif

/*
 * OleStdCreateDC()
 *
 * Purpose:
 *
 * Parameters:
 *
 * Return Value:
 *    SCODE  -  S_OK if successful
 */
STDAPI_(HDC) OleStdCreateDC(DVTARGETDEVICE FAR* ptd)
{
        HDC hdc=NULL;
        LPDEVNAMES lpDevNames;
        LPDEVMODE lpDevMode;
        LPSTR lpszDriverName;
        LPSTR lpszDeviceName;
        LPSTR lpszPortName;

        if (ptd == NULL) {
                hdc = CreateDC("DISPLAY", NULL, NULL, NULL);
                goto errReturn;
        }

        lpDevNames = (LPDEVNAMES) ptd; // offset for size field

        if (ptd->tdExtDevmodeOffset == 0) {
                lpDevMode = NULL;
        }else{
                lpDevMode  = (LPDEVMODE) (/*(LPSTR)*/ptd + ptd->tdExtDevmodeOffset);
        }

        lpszDriverName = (LPSTR) lpDevNames + ptd->tdDriverNameOffset;
        lpszDeviceName = (LPSTR) lpDevNames + ptd->tdDeviceNameOffset;
        lpszPortName   = (LPSTR) lpDevNames + ptd->tdPortNameOffset;

        hdc = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);

errReturn:
        return hdc;
}


/*
 * OleStdCreateIC()
 *
 * Purpose: Same as OleStdCreateDC, except that information context is
 *          created, rather than a whole device context.  (CreateIC is
 *          used rather than CreateDC).
 *          OleStdDeleteDC is still used to delete the information context.
 *
 * Parameters:
 *
 * Return Value:
 *    SCODE  -  S_OK if successful
 */
STDAPI_(HDC) OleStdCreateIC(DVTARGETDEVICE FAR* ptd)
{
        HDC hdcIC=NULL;
        LPDEVNAMES lpDevNames;
        LPDEVMODE lpDevMode;
        LPSTR lpszDriverName;
        LPSTR lpszDeviceName;
        LPSTR lpszPortName;

        if (ptd == NULL) {
                hdcIC = CreateIC("DISPLAY", NULL, NULL, NULL);
                goto errReturn;
        }

        lpDevNames = (LPDEVNAMES) ptd; // offset for size field

        lpDevMode  = (LPDEVMODE) (/*(LPSTR)*/ptd + ptd->tdExtDevmodeOffset);

        lpszDriverName = (LPSTR) lpDevNames + ptd->tdDriverNameOffset;
        lpszDeviceName = (LPSTR) lpDevNames + ptd->tdDeviceNameOffset;
        lpszPortName   = (LPSTR) lpDevNames + ptd->tdPortNameOffset;

        hdcIC = CreateIC(lpszDriverName, lpszDeviceName, lpszPortName, lpDevMode);

errReturn:
        return hdcIC;
}


/*
 * OleStdCreateTargetDevice()
 *
 * Purpose:
 *
 * Parameters:
 *
 * Return Value:
 *    SCODE  -  S_OK if successful
 */
STDAPI_(DVTARGETDEVICE FAR*) OleStdCreateTargetDevice(LPPRINTDLG lpPrintDlg)
{
        DVTARGETDEVICE FAR* ptd=NULL;
        LPDEVNAMES lpDevNames, pDN;
        LPDEVMODE lpDevMode, pDM;
        UINT nMaxOffset;
        LPSTR pszName;
        DWORD dwDevNamesSize, dwDevModeSize, dwPtdSize;

        if ((pDN = (LPDEVNAMES)GlobalLock(lpPrintDlg->hDevNames)) == NULL) {
                goto errReturn;
        }

        if ((pDM = (LPDEVMODE)GlobalLock(lpPrintDlg->hDevMode)) == NULL) {
                goto errReturn;
        }

        nMaxOffset =  (pDN->wDriverOffset > pDN->wDeviceOffset) ?
                pDN->wDriverOffset : pDN->wDeviceOffset ;

        nMaxOffset =  (pDN->wOutputOffset > nMaxOffset) ?
                pDN->wOutputOffset : nMaxOffset ;

        pszName = (LPSTR)pDN + nMaxOffset;

        dwDevNamesSize = (DWORD)(nMaxOffset+lstrlen(pszName) + 1/* NULL term */);
        dwDevModeSize = (DWORD) (pDM->dmSize + pDM->dmDriverExtra);

        dwPtdSize = sizeof(DWORD) + dwDevNamesSize + dwDevModeSize;

        if ((ptd = (DVTARGETDEVICE FAR*)OleStdMalloc(dwPtdSize)) != NULL) {

                // copy in the info
                ptd->tdSize = (UINT)dwPtdSize;

                lpDevNames = (LPDEVNAMES) &ptd->tdDriverNameOffset;
                _fmemcpy(lpDevNames, pDN, (size_t)dwDevNamesSize);

                lpDevMode=(LPDEVMODE)(/*(LPSTR)*/&ptd->tdDriverNameOffset+dwDevNamesSize);
                _fmemcpy(lpDevMode, pDM, (size_t)dwDevModeSize);

                ptd->tdDriverNameOffset += 4 ;
                ptd->tdDeviceNameOffset += 4 ;
                ptd->tdPortNameOffset   += 4 ;
                ptd->tdExtDevmodeOffset = (UINT)dwDevNamesSize + 4 ;
        }

errReturn:
        GlobalUnlock(lpPrintDlg->hDevNames);
        GlobalUnlock(lpPrintDlg->hDevMode);

        return ptd;
}



/*
 * OleStdDeleteTargetDevice()
 *
 * Purpose:
 *
 * Parameters:
 *
 * Return Value:
 *    SCODE  -  S_OK if successful
 */
STDAPI_(BOOL) OleStdDeleteTargetDevice(DVTARGETDEVICE FAR* ptd)
{
        BOOL res=TRUE;

        if (ptd != NULL) {
                OleStdFree(ptd);
        }

        return res;
}



/*
 * OleStdCopyTargetDevice()
 *
 * Purpose:
 *  duplicate a TARGETDEVICE struct. this function allocates memory for
 *  the copy. the caller MUST free the allocated copy when done with it
 *  using the standard allocator returned from CoGetMalloc.
 *  (OleStdFree can be used to free the copy).
 *
 * Parameters:
 *  ptdSrc      pointer to source TARGETDEVICE
 *
 * Return Value:
 *    pointer to allocated copy of ptdSrc
 *    if ptdSrc==NULL then retuns NULL is returned.
 *    if ptdSrc!=NULL and memory allocation fails, then NULL is returned
 */
STDAPI_(DVTARGETDEVICE FAR*) OleStdCopyTargetDevice(DVTARGETDEVICE FAR* ptdSrc)
{
  DVTARGETDEVICE FAR* ptdDest = NULL;

  if (ptdSrc == NULL) {
        return NULL;
  }

  if ((ptdDest = (DVTARGETDEVICE FAR*)OleStdMalloc(ptdSrc->tdSize)) != NULL) {
        _fmemcpy(ptdDest, ptdSrc, (size_t)ptdSrc->tdSize);
  }

  return ptdDest;
}


/*
 * OleStdCopyFormatEtc()
 *
 * Purpose:
 *  Copies the contents of a FORMATETC structure. this function takes
 *  special care to copy correctly copying the pointer to the TARGETDEVICE
 *  contained within the source FORMATETC structure.
 *  if the source FORMATETC has a non-NULL TARGETDEVICE, then a copy
 *  of the TARGETDEVICE will be allocated for the destination of the
 *  FORMATETC (petcDest).
 *
 *  NOTE: the caller MUST free the allocated copy of the TARGETDEVICE
 *  within the destination FORMATETC when done with it
 *  using the standard allocator returned from CoGetMalloc.
 *  (OleStdFree can be used to free the copy).
 *
 * Parameters:
 *  petcDest      pointer to destination FORMATETC
 *  petcSrc       pointer to source FORMATETC
 *
 * Return Value:
 *    returns TRUE is copy is successful; retuns FALSE if not successful
 */
STDAPI_(BOOL) OleStdCopyFormatEtc(LPFORMATETC petcDest, LPFORMATETC petcSrc)
{
  if ((petcDest == NULL) || (petcSrc == NULL)) {
        return FALSE;
  }

  petcDest->cfFormat = petcSrc->cfFormat;
  petcDest->ptd      = OleStdCopyTargetDevice(petcSrc->ptd);
  petcDest->dwAspect = petcSrc->dwAspect;
  petcDest->lindex   = petcSrc->lindex;
  petcDest->tymed    = petcSrc->tymed;

  return TRUE;

}


// returns 0 for exact match, 1 for no match, -1 for partial match (which is
// defined to mean the left is a subset of the right: fewer aspects, null target
// device, fewer medium).

STDAPI_(int) OleStdCompareFormatEtc(FORMATETC FAR* pFetcLeft, FORMATETC FAR* pFetcRight)
{
        BOOL bExact = TRUE;

        if (pFetcLeft->cfFormat != pFetcRight->cfFormat)
                return 1;
        else if (!OleStdCompareTargetDevice (pFetcLeft->ptd, pFetcRight->ptd))
                return 1;
        if (pFetcLeft->dwAspect == pFetcRight->dwAspect)
                // same aspects; equal
                ;
        else if ((pFetcLeft->dwAspect & ~pFetcRight->dwAspect) != 0)
                // left not subset of aspects of right; not equal
                return 1;
        else
                // left subset of right
                bExact = FALSE;

        if (pFetcLeft->tymed == pFetcRight->tymed)
                // same medium flags; equal
                ;
        else if ((pFetcLeft->tymed & ~pFetcRight->tymed) != 0)
                // left not subset of medium flags of right; not equal
                return 1;
        else
                // left subset of right
                bExact = FALSE;

        return bExact ? 0 : -1;
}



STDAPI_(BOOL) OleStdCompareTargetDevice
        (DVTARGETDEVICE FAR* ptdLeft, DVTARGETDEVICE FAR* ptdRight)
{
        if (ptdLeft == ptdRight)
                // same address of td; must be same (handles NULL case)
                return TRUE;
        else if ((ptdRight == NULL) || (ptdLeft == NULL))
                return FALSE;
        else if (ptdLeft->tdSize != ptdRight->tdSize)
                // different sizes, not equal
                return FALSE;
#ifdef WIN32
        else if (memcmp(ptdLeft, ptdRight, ptdLeft->tdSize) != 0)
#else
        else if (_fmemcmp(ptdLeft, ptdRight, (int)ptdLeft->tdSize) != 0)
#endif
                // not same target device, not equal
                return FALSE;

        return TRUE;
}
