/*++

Copyright (c) 1996-1999  Microsoft Corporation

Module Name:

    ib587res.c

Abstract:

    Implementation of GPD command callback for "test.gpd":
        OEMCommandCallback

Environment:

    Windows NT Unidrv driver

--*/

#include "pdev.h"

#include <windows.h>
#include <stdio.h>

#include <strsafe.h>

HANDLE	RevertToPrinterSelf( VOID );
BOOL	ImpersonatePrinterClient( HANDLE );

/*--------------------------------------------------------------------------*/
/*                             G L O B A L  V A L U E                         */
/*--------------------------------------------------------------------------*/

//Command strings

//
const BYTE CMD_BEGIN_DOC_1[] = {0x1B,0x7E,0xB0,0x00,0x12,0x01} ;
const BYTE CMD_BEGIN_DOC_2[] = {0x01,0x01,0x00} ;
const BYTE CMD_BEGIN_DOC_3[] = {0x02,0x02,0xFF,0xFF} ;
const BYTE CMD_BEGIN_DOC_4[] = {0x03,0x02,0xFF,0xFF} ;
const BYTE CMD_BEGIN_DOC_5[] = {0x04,0x04,0xFF,0xFF,0xFF,0xFF} ;
// ISSUE-2002/3/18-takashim - Not sure why CMD_BEGIN_PAGE[] was defined as 2 bytes.
//const BYTE CMD_BEGIN_PAGE[]    = {0xD4, 0x00} ;
const BYTE CMD_BEGIN_PAGE[]    = {0xD4} ;
const BYTE CMD_END_JOB[] = {0x1B,0x7E,0xB0,0x00,0x04,0x01,0x01,0x01,0x01} ;
const BYTE CMD_END_PAGE[] = {0x20};

//SetPac
#define CMD_SETPAC pOEM->SetPac

#define CMD_SETPAC_FRONT_TRAY_PAPER_SIZE    4
#define CMD_SETPAC_INPUT_BIN                5
#define CMD_SETPAC_RESOLUTION               12
#define CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE  14
#define CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE  15
#define CMD_SETPAC_PAGE_LENGTH              19 // 4 bytes
#define CMD_SETPAC_TONER_SAVE_MODE          25
#define CMD_SETPAC_CUSTOM_DOTS_PER_LINE     26 // 2 bytes
#define CMD_SETPAC_CUSTOM_LINES_PER_PAGE    28 // 2 bytes

const BYTE CMD_SETPAC_TMPL[
        CMD_SETPAC_SIZE]    ={ 0xD7,
                       0x01,
                       0xD0,
                       0x1D, //CommandLength
                       0x00, //Front tray paper size
                       0x00, //Input-bin
                       0x01,
                       0x04, //Bit-assign1
                       0xD9, //Bit-assign2
                       0x04, //EET
                       0x02, //PrintDensity
                       0x01, 
                       0x00, //Resolution
                       0x01,
                       0x00, //1st cassette paper size
                       0x00, //2nd cassette paper size
                       0x0F, //Time to Power Save
                       0x00, 
                       0x01, //Compression Mode
                       0x00,0x00,0x00,0x00, //PageLength
                       0x07, 
                       0x00, //Number of Copies
                       0x00, //Toner save mode
                       0x00,0x00, //Dot per line for custom size
                       0x00,0x00, //Data lines per page for custom size
                       0x00} ;

const BYTE Mask[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01} ;

const POINTL phySize300[] = {
//    Width,Height Physical paper size for 300dpi
    {3416,4872},    //A3
    {2392,3416},    //A4
    {1672,2392},    //A5
    {2944,4208},    //B4
    {2056,2944},    //B5
    {1088,1656},    //PostCard
    {2456,3208},    //Letter
    {2456,4112},    //Legal
    {0000,0000},    //user define
};
const POINTL phySize600[] = {
//    Width,Height   Physical paper size for 600dpi
    {6832,9736},    //A3
    {4776,6832},    //A4
    {3336,4776},    //A5
    {5888,8416},    //B4
    {4112,5888},    //B5
    {2176,3312},    //PostCard
    {4912,6416},    //Letter
    {4912,8216},    //Legal
    {0000,0000},    //user define
};


/******************* FUNCTIONS *************************/
BOOL MyDeleteFile(PDEVOBJ pdevobj, LPSB lpsb) ;
BOOL InitSpoolBuffer(LPSB lpsb) ;
BOOL MyCreateFile(PDEVOBJ pdevobj, LPSB lpsb) ;
BOOL MySpool(PDEVOBJ pdevobj, LPSB lpsb, PBYTE pBuf, DWORD dwLen) ;
BOOL SpoolOut(PDEVOBJ pdevobj, LPSB lpsb) ;
BOOL MyEndDoc(PDEVOBJ pdevobj) ;
BOOL WriteFileForP_Paper(PDEVOBJ pdevobj, PBYTE pBuf, DWORD dwLen) ;
BOOL WriteFileForL_Paper(PDEVOBJ pdevobj, PBYTE pBuf, DWORD dwLen) ;
BOOL FillPageRestData(PDEVOBJ pdevobj) ;
BOOL SpoolWhiteData(PDEVOBJ pdevobj, DWORD dwWhiteLen, BOOL fComp) ;
BOOL SendPageData(PDEVOBJ pdevobj, PBYTE pSrcImage, DWORD dwLen) ;
BOOL SpoolOutChangedData(PDEVOBJ pdevobj, LPSB lpsb) ;
WORD GetPrintableArea(WORD physSize, INT iRes) ;
BOOL AllocTempBuffer(PIBMPDEV pOEM, DWORD dwNewBufLen) ;
BOOL MyEndPage(PDEVOBJ pdevobj) ;
BOOL MyStartDoc(PDEVOBJ pdevobj) ;

BOOL SpoolOutCompStart(PSOCOMP pSoc);
BOOL SpoolOutCompEnd(PSOCOMP pSoc, PDEVOBJ pdevobj, LPSB psb);
BOOL SpoolOutComp(PSOCOMP pSoc, PDEVOBJ pdevobj, LPSB psb,
    PBYTE pjBuf, DWORD dwLen);

/*****************************************************************************/
/*                                                                             */
/*    Module:         IB587RES.DLL                                              *
/*                                                                             */
/*    Function:        OEMEnablePDEV                                             */
/*                                                                             */
/*    Syntax:         PDEVOEM APIENTRY OEMEnablePDEV(                          */
/*                                        PDEVOBJ         pdevobj,             */
/*                                        PWSTR            pPrinterName,         */
/*                                        ULONG            cPatterns,             */
/*                                        HSURF           *phsurfPatterns,      */
/*                                        ULONG            cjGdiInfo,             */
/*                                        GDIINFO        *pGdiInfo,             */
/*                                        ULONG            cjDevInfo,             */
/*                                        DEVINFO        *pDevInfo,             */
/*                                        DRVENABLEDATA  *pded)                 */
/*                                                                             */
/*    Description:    Allocate buffer of private data to pdevobj                 */
/*                                                                             */
/*****************************************************************************/
PDEVOEM APIENTRY
OEMEnablePDEV(
    PDEVOBJ         pdevobj,
    PWSTR            pPrinterName,
    ULONG            cPatterns,
    HSURF           *phsurfPatterns,
    ULONG            cjGdiInfo,
    GDIINFO        *pGdiInfo,
    ULONG            cjDevInfo,
    DEVINFO        *pDevInfo,
    DRVENABLEDATA  *pded)
{
    PIBMPDEV    pOEM;

    if (!VALID_PDEVOBJ(pdevobj))
    {
        return NULL;
    }

    if(!pdevobj->pdevOEM)
    {
        if(!(pdevobj->pdevOEM = MemAlloc(sizeof(IBMPDEV))))
        {
            //DBGPRINT(DBG_WARNING, (ERRORTEXT("OEMEnablePDEV:Memory alloc failed.\n")));
            return NULL;
        }
    }

    pOEM = (PIBMPDEV)(pdevobj->pdevOEM);

    // Setup pdev specific conrol block fields
    ZeroMemory(pOEM, sizeof(IBMPDEV));
    CopyMemory(pOEM->SetPac, CMD_SETPAC_TMPL, sizeof(CMD_SETPAC_TMPL));

    return pdevobj->pdevOEM;
}


/*****************************************************************************/
/*                                                                             */
/*    Module:         IB587RES.DLL                                              */
/*                                                                             */
/*    Function:        OEMDisablePDEV                                             */
/*                                                                             */
/*    Description:    Free buffer of private data                              */
/*                                                                             */
/*****************************************************************************/
VOID APIENTRY
OEMDisablePDEV(
    PDEVOBJ     pdevobj)
{
    if (!VALID_PDEVOBJ(pdevobj))
    {
        return;
    }

    if(pdevobj->pdevOEM)
    {
        if (((PIBMPDEV)(pdevobj->pdevOEM))->pTempImage) {
            MemFree(((PIBMPDEV)(pdevobj->pdevOEM))->pTempImage);
            ((PIBMPDEV)(pdevobj->pdevOEM))->pTempImage = 0;
        }

        MemFree(pdevobj->pdevOEM);
        pdevobj->pdevOEM = NULL;
    }
    return;
}

BOOL APIENTRY OEMResetPDEV(
    PDEVOBJ pdevobjOld,
    PDEVOBJ pdevobjNew)
{
    PIBMPDEV pOEMOld, pOEMNew;
    PBYTE pTemp;
    DWORD dwTemp;

    if (!VALID_PDEVOBJ(pdevobjOld)
            || !VALID_PDEVOBJ(pdevobjNew))
    {
        return FALSE;
    }

    pOEMOld = (PIBMPDEV)pdevobjOld->pdevOEM;
    pOEMNew = (PIBMPDEV)pdevobjNew->pdevOEM;

    if (pOEMOld != NULL && pOEMNew != NULL) {

        // Save pointer and length
        pTemp = pOEMNew->pTempImage;
        dwTemp = pOEMNew->dwTempBufLen;

        *pOEMNew = *pOEMOld;

        // Restore..
        pOEMNew->pTempImage = pTemp;
        pOEMNew->dwTempBufLen = dwTemp;
    }

    return TRUE;
}

/*****************************************************************************/
/*                                                                             */
/*    Module:    OEMFilterGraphics                                             */
/*                                                                             */
/*    Function:                                                                 */
/*                                                                             */
/*    Syntax:    BOOL APIENTRY OEMFilterGraphics(PDEVOBJ, PBYTE, DWORD)         */
/*                                                                             */
/*    Input:       pdevobj       address of PDEVICE structure                      */
/*               pBuf        points to buffer of graphics data                 */
/*               dwLen       length of buffer in bytes                         */
/*                                                                             */
/*    Output:    BOOL                                                          */
/*                                                                             */
/*    Notice:    nFunction and Escape numbers are the same                     */
/*                                                                             */
/*****************************************************************************/
BOOL
APIENTRY
OEMFilterGraphics(
    PDEVOBJ pdevobj,
    PBYTE pBuf,
    DWORD dwLen)
{
    PIBMPDEV    pOEM;
    BOOL bRet;

    if (!VALID_PDEVOBJ(pdevobj))
    {
        return FALSE;
    }

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    bRet = TRUE;

    if(pOEM->fChangeDirection) {
        bRet = WriteFileForL_Paper(pdevobj, pBuf, dwLen);

    }else{
        bRet = WriteFileForP_Paper(pdevobj, pBuf, dwLen);
    }

    return bRet;
}

/*****************************************************************************/
/*                                                                             */
/*    Module:    OEMCommandCallback                                             */
/*                                                                             */
/*    Function:                                                                 */
/*                                                                             */
/*    Syntax:    INT APIENTRY OEMCommandCallback(PDEVOBJ,DWORD,DWORD,PDWORD)     */
/*                                                                             */
/*    Input:       pdevobj                                                         */
/*               dwCmdCbID                                                     */
/*               dwCount                                                         */
/*               pdwParams                                                     */
/*                                                                             */
/*    Output:    INT                                                             */
/*                                                                             */
/*    Notice:                                                                  */
/*                                                                             */
/*****************************************************************************/
INT APIENTRY
OEMCommandCallback(
    PDEVOBJ pdevobj,    // Points to private data required by the Unidriver.dll
    DWORD    dwCmdCbID,    // Callback ID
    DWORD    dwCount,    // Counts of command parameter
    PDWORD    pdwParams ) // points to values of command params
{
    PIBMPDEV       pOEM;
    WORD            wPhysWidth;
    WORD            wPhysHeight;
    WORD            wDataLen ;
    WORD            wLines ;
    WORD            wNumOfByte ;
    POINTL            ptlUserDefSize;

    BYTE            byOutput[64];
    DWORD            dwNeeded;
    DWORD            dwOptionsReturned;
    INT iRet;

    if (!VALID_PDEVOBJ(pdevobj))
    {
        return FALSE;
    }

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    iRet = 0;

    switch(dwCmdCbID)
    {

        case PAGECONTROL_BEGIN_DOC:
            if (!InitSpoolBuffer(&(pOEM->sb)))
                goto fail;

            if (!MyCreateFile(pdevobj, &(pOEM->sb)))
                goto fail;
            if (!MyCreateFile(pdevobj, &(pOEM->sbcomp)))
                goto fail;

            pOEM->fChangeDirection = FALSE ;
            pOEM->sPageNum = 0 ;

            if (!MyStartDoc(pdevobj))
                goto fail;

            break;

        case PAGECONTROL_BEGIN_PAGE:
            pOEM->dwCurCursorY = 0 ;
            pOEM->dwOffset = 0 ;
            pOEM->sPageNum ++ ;

            if(pOEM->fChangeDirection == FALSE) {
                if (!MySpool(pdevobj, &(pOEM->sb),
                            (PBYTE)CMD_BEGIN_PAGE, sizeof(CMD_BEGIN_PAGE)))
                    goto fail;
                if (!SpoolOutCompStart(&pOEM->Soc))
                    goto fail;
            }

            break;

        case PAGECONTROL_END_PAGE:
            if(pOEM->fChangeDirection == FALSE){
                if (!FillPageRestData(pdevobj))
                    goto fail;
                if (!SpoolOutCompEnd(&pOEM->Soc, pdevobj, &pOEM->sb))
                    goto fail;
                if (!MySpool(pdevobj,&(pOEM->sb),
                    (PBYTE)CMD_END_PAGE, sizeof(CMD_END_PAGE)))
                    goto fail;
            }else{
               if (!SpoolOutChangedData(pdevobj, &(pOEM->sbcomp)))
                   goto fail;
            }

            if (!MyEndPage(pdevobj))
                goto fail;
            
            break;

        case PAGECONTROL_ABORT_DOC:
        case PAGECONTROL_END_DOC:
                       
            if (!MyEndDoc(pdevobj))
                goto fail;
            break;

        case RESOLUTION_300:
            pOEM->ulHorzRes = 300;
            pOEM->ulVertRes = 300;

            CMD_SETPAC[CMD_SETPAC_RESOLUTION] = 0x02 ;
            
            if (pOEM->sPaperSize < PHYS_PAPER_BASE
                    || pOEM->sPaperSize > PHYS_PAPER_MAX)
            {
                goto fail;
            }
            else if( pOEM->sPaperSize == PHYS_PAPER_UNFIXED){
                pOEM->szlPhysSize.cx = PARAM(pdwParams, 0);
                pOEM->szlPhysSize.cy = PARAM(pdwParams, 1);

                ptlUserDefSize.x = GetPrintableArea((WORD)pOEM->szlPhysSize.cx, RESOLUTION_300);
                ptlUserDefSize.y = GetPrintableArea((WORD)pOEM->szlPhysSize.cy, RESOLUTION_300);
                pOEM->ptlLogSize = ptlUserDefSize;

                CMD_SETPAC[CMD_SETPAC_CUSTOM_DOTS_PER_LINE] = LOBYTE((WORD)(ptlUserDefSize.x));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_DOTS_PER_LINE + 1] = HIBYTE((WORD)(ptlUserDefSize.x));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_LINES_PER_PAGE] = LOBYTE((WORD)(ptlUserDefSize.y));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_LINES_PER_PAGE + 1] = HIBYTE((WORD)(ptlUserDefSize.y));
            }
            else
            {
                pOEM->ptlLogSize = phySize300[
                        pOEM->sPaperSize-PHYS_PAPER_BASE];
            }

            break;

        case RESOLUTION_600:
            pOEM->ulHorzRes = 600;
            pOEM->ulVertRes = 600;
            pOEM->ptlLogSize = phySize600[pOEM->sPaperSize-50];
            CMD_SETPAC[CMD_SETPAC_RESOLUTION] = 0x20 ;

            if (pOEM->sPaperSize < PHYS_PAPER_BASE
                    || pOEM->sPaperSize > PHYS_PAPER_MAX)
            {
                goto fail;
            }
            else if( pOEM->sPaperSize == PHYS_PAPER_UNFIXED){
                pOEM->szlPhysSize.cx = PARAM(pdwParams, 0);
                pOEM->szlPhysSize.cy = PARAM(pdwParams, 1);

                ptlUserDefSize.x = GetPrintableArea((WORD)pOEM->szlPhysSize.cx, RESOLUTION_600);
                ptlUserDefSize.y = GetPrintableArea((WORD)pOEM->szlPhysSize.cy, RESOLUTION_600);
                pOEM->ptlLogSize = ptlUserDefSize;

                CMD_SETPAC[CMD_SETPAC_CUSTOM_DOTS_PER_LINE] = LOBYTE((WORD)(ptlUserDefSize.x));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_DOTS_PER_LINE + 1] = HIBYTE((WORD)(ptlUserDefSize.x));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_LINES_PER_PAGE] = LOBYTE((WORD)(ptlUserDefSize.y));
                CMD_SETPAC[CMD_SETPAC_CUSTOM_LINES_PER_PAGE + 1] = HIBYTE((WORD)(ptlUserDefSize.y));
            }
            else {
                pOEM->ptlLogSize = phySize600[
                         pOEM->sPaperSize-PHYS_PAPER_BASE];
            }
            break;

        case SEND_BLOCK_DATA:
            wNumOfByte = (WORD)PARAM(pdwParams, 0);

            pOEM->wImgHeight = (WORD)PARAM(pdwParams, 1);
            pOEM->wImgWidth = (WORD)PARAM(pdwParams, 2);
            break;

        case ORIENTATION_PORTRAIT:                   // 28
        case ORIENTATION_LANDSCAPE:                 // 29
             switch(pOEM->sPaperSize){
                case PHYS_PAPER_A3 :
                case PHYS_PAPER_B4 :
                case PHYS_PAPER_LEGAL :
                case PHYS_PAPER_POSTCARD :
                    pOEM->fChangeDirection = FALSE ;
                    pOEM->fComp = TRUE ;
                    break;

                case PHYS_PAPER_A4 :
                case PHYS_PAPER_A5 :
                case PHYS_PAPER_B5 :
                case PHYS_PAPER_LETTER :
                    pOEM->fChangeDirection = TRUE ;
                    pOEM->fComp = FALSE ;
                    break;

                case PHYS_PAPER_UNFIXED :           /* Paper is not rotated in UNFIXED case */
                    pOEM->fChangeDirection = FALSE ;
                    pOEM->fComp = TRUE ;
                    break;
            }
            break;

        case PHYS_PAPER_A3:                 // 50
             pOEM->sPaperSize = PHYS_PAPER_A3 ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x04 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x04 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x04 ;
             break ;
        case PHYS_PAPER_A4:                 // 51
             pOEM->sPaperSize = PHYS_PAPER_A4 ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x83 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x83 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x83 ;
             break ;
        case PHYS_PAPER_B4:                 // 54
             pOEM->sPaperSize = PHYS_PAPER_B4 ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x07 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x07 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x07 ;
             break ;
        case PHYS_PAPER_LETTER:             // 57
             pOEM->sPaperSize = PHYS_PAPER_LETTER ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x90 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x90 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x90 ;
             break ;
        case PHYS_PAPER_LEGAL:                // 58
             pOEM->sPaperSize = PHYS_PAPER_LEGAL ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x11 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x11 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x11 ;
             break ;

        case PHYS_PAPER_B5:                 // 55
             pOEM->sPaperSize = PHYS_PAPER_B5 ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x86 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x86 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x86 ;
             break ;
        case PHYS_PAPER_A5:                 // 52
             pOEM->sPaperSize = PHYS_PAPER_A5 ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x82 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x82 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x82 ;
             break ;

        case PHYS_PAPER_POSTCARD:            // 59
             pOEM->sPaperSize = PHYS_PAPER_POSTCARD ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x17 ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x17 ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x17 ;
             break ;

        case PHYS_PAPER_UNFIXED:            // 60
             pOEM->sPaperSize = PHYS_PAPER_UNFIXED ;
             CMD_SETPAC[CMD_SETPAC_FRONT_TRAY_PAPER_SIZE] = 0x3F ;
             CMD_SETPAC[CMD_SETPAC_1ST_CASSETTE_PAPER_SIZE] = 0x3F ;
             CMD_SETPAC[CMD_SETPAC_2ND_CASSETTE_PAPER_SIZE] = 0x3F ;

             break ;

        case PAPER_SRC_FTRAY:
             CMD_SETPAC[CMD_SETPAC_INPUT_BIN] = 0x01 ;
             break ;

        case PAPER_SRC_CAS1:
            CMD_SETPAC[CMD_SETPAC_INPUT_BIN] = 0x02 ;
            break;

        case PAPER_SRC_CAS2:
            CMD_SETPAC[CMD_SETPAC_INPUT_BIN] = 0x04 ;
            break;

        case PAPER_SRC_AUTO:
            CMD_SETPAC[CMD_SETPAC_INPUT_BIN] = 0x04 ;
            break;


        case TONER_SAVE_MEDIUM:                // 100
            CMD_SETPAC[CMD_SETPAC_TONER_SAVE_MODE] = 0x02 ;
            break;

        case TONER_SAVE_DARK:                // 101
            CMD_SETPAC[CMD_SETPAC_TONER_SAVE_MODE] = 0x04 ;
            break;

        case TONER_SAVE_LIGHT:                // 102
            CMD_SETPAC[CMD_SETPAC_TONER_SAVE_MODE] = 0x01 ;
            break;


        case PAGECONTROL_MULTI_COPIES:
            CMD_SETPAC[24] = (BYTE)PARAM(pdwParams, 0);
            pOEM->sCopyNum = (BYTE)PARAM(pdwParams, 0);
            break;
        
        case Y_REL_MOVE :

            if (0 == pOEM->ulHorzRes)
                goto fail;

            pOEM->dwYmove=(WORD)*pdwParams/(MASTERUNIT/(WORD)pOEM->ulHorzRes);

// ISSUE-2002/3/18-takashim - Faking Unidrv here?
// iRet = 0; below is intentional:  Retuning dwYmove will cause
// incorrect outputs.
// DestYRel in GPD means the coordinate relative to the current
// cursor position.  Here, minidriver is always returning 0 (no move)
// to Unidrv, so it is always absolute coordinate (relative to
// the origin)?

            if(pOEM->dwCurCursorY < pOEM->dwYmove){
                pOEM->dwYmove -= pOEM->dwCurCursorY ;
            }else{
                pOEM->dwYmove = 0 ;
            }

//            iRet = pOEM->dwYmove;
            iRet = 0;

            break;
            

        default:
            break;
    }
    return iRet;

fail:
    return -1;
}


/*****************************************************************************/
/*                                                                             */
/*    Module:    GetPrintableArea                                              */
/*                                                                             */
/*    Function:  Calculate PrintableArea for user defined paper                 */
/*                                                                             */
/*    Syntax:    WORD GetPrintableArea(WORD physSize, INT iRes)                 */
/*                                                                             */
/*    Input:       physSize                                                      */
/*               iRes                                                          */
/*                                                                             */
/*    Output:    WORD                                                          */
/*                                                                             */
/*    Notice:                                                                  */
/*                                                                             */
/*****************************************************************************/
WORD GetPrintableArea(WORD physSize, INT iRes)
{
    DWORD dwArea ;
    DWORD dwPhysSizeMMx10 = physSize * 254 / MASTERUNIT;

    /* Unit of phySize is MASTERUNIT(=1200) */

    if(iRes == RESOLUTION_300){
        dwArea = (((WORD)(( ( (DWORD)(dwPhysSizeMMx10*300/25.4) -
                            2*( (DWORD)(4*300*10/25.4) ) ) / 10 +7)/8))) * 8;
    }else{
        dwArea = (((WORD)(( ( (DWORD)(dwPhysSizeMMx10*600/25.4) -
                            2*( (DWORD)(4*600*10/25.4) ) ) / 10 +7)/8))) * 8;
    }

    return (WORD)dwArea ;
}

// NOTICE-2002/3/18/-takashim - Comment
// // #94193: shold create temp. file on spooler directory.
//

/*++

Routine Description:

  This function comes up with a name for a spool file that we should be
  able to write to.

  Note: The file name returned has already been created.

Arguments:

  hPrinter - handle to the printer that we want a spool file for.

  ppwchSpoolFileName: pointer that will receive an allocated buffer
                      containing the file name to spool to.  CALLER
                      MUST FREE.  Use LocalFree().


Return Value:

  TRUE if everything goes as expected.
  FALSE if anything goes wrong.

--*/

BOOL
GetSpoolFileName(
  IN HANDLE hPrinter,
  IN OUT PWCHAR pwchSpoolPath
)
{
  PBYTE         pBuffer = NULL;
  DWORD         dwAllocSize;
  DWORD         dwNeeded = 0;
  DWORD         dwRetval;
  HANDLE        hToken=NULL;

  hToken = RevertToPrinterSelf();

  //
  //  In order to find out where the spooler's directory is, we add
  //  call GetPrinterData with DefaultSpoolDirectory.
  //

  dwAllocSize = ( MAX_PATH ) * sizeof (WCHAR);

  for (;;)
  {
    pBuffer = LocalAlloc( LMEM_FIXED, dwAllocSize );

    if ( pBuffer == NULL )
    {
      ERR((DLLTEXT("LocalAlloc faild, %d\n"), GetLastError()));
      goto Failure;
    }

    if ( GetPrinterData( hPrinter,
                         SPLREG_DEFAULT_SPOOL_DIRECTORY,
                         NULL,
                         pBuffer,
                         dwAllocSize,
                         &dwNeeded ) == ERROR_SUCCESS )
    {
      break;
    }

    if ( ( dwNeeded < dwAllocSize ) ||( GetLastError() != ERROR_MORE_DATA ))
    {
      ERR((DLLTEXT("GetPrinterData failed in a non-understood way.\n")));
      goto Failure;
    }

    //
    // Free the current buffer and increase the size that we try to allocate
    // next time around.
    //

    LocalFree( pBuffer );

    dwAllocSize = dwNeeded;
  }

// FUTURE-2002/3/18-takashim - Temp file path restricted to ANSI.
// According to the SDK document, the pathname handled by GetTempFileName
// must be consist of ANSI characters.  What happens with double-byte
// characters, etc??

  if( !GetTempFileName( (LPWSTR)pBuffer, TEMP_NAME_PREFIX, 0, pwchSpoolPath ))
  {
      goto Failure;
  }

  //
  //  At this point, the spool file name should be done.  Free the structure
  //  we used to get the spooler temp dir and return.
  //

  LocalFree( pBuffer );

  if (NULL != hToken) {
      if (!ImpersonatePrinterClient(hToken))
      {
        // failure..
        return FALSE;
      }
  }

  return( TRUE );

Failure:

  //
  //  Clean up and fail.
  //
  if ( pBuffer != NULL )
  {
    LocalFree( pBuffer );
  }

  if (hToken != NULL)
  {
      (void)ImpersonatePrinterClient(hToken);
  }
  return ( FALSE );
}

//SPLBUF is used for control temp files.
//This printer need the number of bytes of whole page data.
BOOL InitSpoolBuffer(LPSB lpsb)
{
    lpsb->dwWrite = 0 ;
    lpsb->TempName[0] = __TEXT('\0') ;
    lpsb->hFile = INVALID_HANDLE_VALUE ;

    return TRUE;
}

BOOL MyCreateFile(PDEVOBJ pdevobj, LPSB lpsb)
{
    HANDLE hToken = NULL;
    BOOL bRet = FALSE;

    if (!GetSpoolFileName(pdevobj->hPrinter, lpsb->TempName)) {
        //DBGPRINT(DBG_WARNING, ("GetSpoolFileName failed.\n"));
        goto fail;
    }

    hToken = RevertToPrinterSelf();

    lpsb->hFile = CreateFile((LPCTSTR)lpsb->TempName,
                     (GENERIC_READ | GENERIC_WRITE), 
                     0,                             
                     NULL,                            
                     CREATE_ALWAYS,                 
                     FILE_ATTRIBUTE_NORMAL,         
                     NULL) ;

    if(lpsb->hFile == INVALID_HANDLE_VALUE)
    {
        //DBGPRINT(DBG_WARNING, ("Tmp file cannot create.\n"));
        DeleteFile(lpsb->TempName);
        lpsb->TempName[0] = __TEXT('\0') ;
        goto fail;
    }
    bRet = TRUE;

fail:
    if (hToken) (void)ImpersonatePrinterClient(hToken);
    return bRet ;
}

BOOL MyDeleteFile(PDEVOBJ pdevobj, LPSB lpsb)
{    
    HANDLE hToken = NULL;
    BOOL bRet = FALSE;

    if(lpsb->hFile != INVALID_HANDLE_VALUE){

        if (0 == CloseHandle(lpsb->hFile)) {
            //DBGPRINT(DBG_WARNING, ("CloseHandle error %d\n"));
            goto fail;
        }
        lpsb->hFile = INVALID_HANDLE_VALUE ;
        hToken = RevertToPrinterSelf();
        if (0 == DeleteFile(lpsb->TempName)) {
            //DBGPRINT(DBG_WARNING, ("DeleteName error %d\n",GetLastError()));
            goto fail;
        }
        lpsb->TempName[0] = __TEXT('\0');

    }
    bRet = TRUE;

fail:
    if (hToken) (void)ImpersonatePrinterClient(hToken);
    return bRet;
}

//Spool page data to temp file
BOOL MySpool
    (PDEVOBJ pdevobj,
     LPSB  lpsb,
     PBYTE pBuf,
     DWORD dwLen)
{
    DWORD dwTemp, dwTemp2;
    BYTE *pTemp;

    if (lpsb->hFile != INVALID_HANDLE_VALUE) {

        pTemp = pBuf;
        dwTemp = dwLen;
        while (dwTemp > 0) {

            if (0 == WriteFile(lpsb->hFile,
                               pTemp,
                               dwTemp,
                               &dwTemp2,
                               NULL)
                    || dwTemp2 > dwTemp) {

                ERR((DLLTEXT("WriteFile error in CacheData %d.\n"),
                    GetLastError()));
                return FALSE;
            }
            pTemp += dwTemp2;
            dwTemp -= dwTemp2;
            lpsb->dwWrite += dwTemp2 ;
        }
        return TRUE;
    }
    else {
        return WRITESPOOLBUF(pdevobj, pBuf, dwLen);
    }
}

//Dump out temp file to printer
BOOL
SpoolOut(PDEVOBJ pdevobj, LPSB lpsb)
{
 
   DWORD dwSize, dwTemp, dwTemp2;
   HANDLE hFile;

    BYTE  Buf[SPOOL_OUT_BUF_SIZE];

    hFile = lpsb->hFile ;
    dwSize = lpsb->dwWrite ;

    VERBOSE(("dwSize=%ld\n", dwSize));

    if (0L != SetFilePointer(hFile, 0L, NULL, FILE_BEGIN)) {

        ERR((DLLTEXT("SetFilePointer failed %d\n"),
            GetLastError()));
        return FALSE;
    }

    for ( ; dwSize > 0; dwSize -= dwTemp2) {

        dwTemp = ((SPOOL_OUT_BUF_SIZE < dwSize)
            ? SPOOL_OUT_BUF_SIZE : dwSize);

        if (0 == ReadFile(hFile, Buf, dwTemp, &dwTemp2, NULL)
                || dwTemp2 > dwTemp) {
            ERR((DLLTEXT("ReadFile error in SendCachedData.\n")));
            return FALSE;
        }

        if (dwTemp2 > 0) {
            if (!WRITESPOOLBUF(pdevobj, Buf, dwTemp2))
                return FALSE;
        }
    }

    return TRUE;
}

BOOL MyStartDoc(PDEVOBJ pdevobj)
{
    return
    WRITESPOOLBUF(pdevobj, (PBYTE)CMD_BEGIN_DOC_1, sizeof(CMD_BEGIN_DOC_1)) &&
    WRITESPOOLBUF(pdevobj, (PBYTE)CMD_BEGIN_DOC_2, sizeof(CMD_BEGIN_DOC_2)) &&
    WRITESPOOLBUF(pdevobj, (PBYTE)CMD_BEGIN_DOC_3, sizeof(CMD_BEGIN_DOC_3)) &&
    WRITESPOOLBUF(pdevobj, (PBYTE)CMD_BEGIN_DOC_4, sizeof(CMD_BEGIN_DOC_4)) &&
    WRITESPOOLBUF(pdevobj, (PBYTE)CMD_BEGIN_DOC_5, sizeof(CMD_BEGIN_DOC_5));
}

BOOL MyEndPage(PDEVOBJ pdevobj)
{
    PIBMPDEV    pOEM;
    LPSB        lpsb, lpsbco ;
    DWORD        dwPageLen ;
    WORD        wTmph, wTmpl ;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;
    lpsb = &(pOEM->sb) ;
    lpsbco = &(pOEM->sbcomp) ;

    if(pOEM->fChangeDirection == FALSE) {
        dwPageLen = lpsb->dwWrite;
    }
    else {
        dwPageLen = lpsbco->dwWrite ;
    }

// NOTICE-2002/3/18-takashim - What is this?

    dwPageLen -= 3 ; //End page Command Len

    VERBOSE(("MyEndPage - dwPageLen=%ld\n",
        dwPageLen));

    wTmpl = LOWORD(dwPageLen) ;
    wTmph = HIWORD(dwPageLen) ;
    
    CMD_SETPAC[CMD_SETPAC_PAGE_LENGTH] = LOBYTE(wTmpl);
    CMD_SETPAC[CMD_SETPAC_PAGE_LENGTH + 1] = HIBYTE(wTmpl);
    CMD_SETPAC[CMD_SETPAC_PAGE_LENGTH + 2] = LOBYTE(wTmph);
    CMD_SETPAC[CMD_SETPAC_PAGE_LENGTH + 3] = HIBYTE(wTmph);

    if (!WRITESPOOLBUF(pdevobj, CMD_SETPAC, sizeof(CMD_SETPAC)))
        return FALSE;

    if(pOEM->fChangeDirection == FALSE){
        if (!SpoolOut(pdevobj, lpsb))
            return FALSE;
    }else{
        if (!SpoolOut(pdevobj, lpsbco))
            return FALSE;
    }

    //InitFiles
    lpsbco->dwWrite = 0 ;
    lpsb->dwWrite = 0 ;

    if(INVALID_SET_FILE_POINTER==SetFilePointer(lpsb->hFile,0,NULL,FILE_BEGIN)){
        ERR((DLLTEXT("SetFilePointer failed %d\n"),
             GetLastError()));
        return FALSE;
    }

    if(INVALID_SET_FILE_POINTER==SetFilePointer(lpsbco->hFile,0,NULL,FILE_BEGIN)){
        ERR((DLLTEXT("SetFilePointer failed %d\n"),
             GetLastError()));
        return FALSE;
    }

    return TRUE;
}

BOOL MyEndDoc(PDEVOBJ pdevobj)
{
    PIBMPDEV    pOEM;
    LPSB        lpsb, lpsbco ;
    WORD        wTmph, wTmpl ;
    DWORD        dwPageLen ;
    SHORT        i ;
    LPPD        lppdTemp ;
    BOOL        bRet = FALSE;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;
    lpsb = &(pOEM->sb) ;
    lpsbco = &(pOEM->sbcomp) ;


    if (!WRITESPOOLBUF(pdevobj, (PBYTE)CMD_END_JOB, sizeof(CMD_END_JOB)))
        goto fail;

    if (!MyDeleteFile(pdevobj, lpsb))
        goto fail;
    if (!MyDeleteFile(pdevobj, lpsbco))
        goto fail;
    bRet = TRUE;

fail:
    return bRet;
}

BOOL WriteFileForP_Paper(PDEVOBJ pdevobj, PBYTE pBuf, DWORD dwLen)
{
    PIBMPDEV           pOEM;
    ULONG                ulHorzPixel;
    WORD                wCompLen;
    DWORD                dwWhiteLen ;
    DWORD                dwTmp ;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    if (pOEM->dwYmove > 0) {

        dwWhiteLen = pOEM->wImgWidth * pOEM->dwYmove;

        if (!SpoolWhiteData(pdevobj, dwWhiteLen, TRUE))
            return FALSE;

        pOEM->dwCurCursorY += pOEM->dwYmove;
        pOEM->dwYmove = 0;
    }

    pOEM->dwCurCursorY += dwLen/pOEM->wImgWidth - 1 ;

    return SendPageData(pdevobj, pBuf, dwLen) ;
}

BOOL WriteFileForL_Paper(PDEVOBJ pdevobj, PBYTE pBuf, DWORD dwLen)
{
    PIBMPDEV           pOEM;
    ULONG                ulHorzPixel;
    WORD                wCompLen;
    DWORD                dwWhiteLen ;

    DWORD i, j;
    DWORD dwHeight, dwWidth;
    PBYTE pTemp;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    if (pOEM->dwYmove > 0) {

        dwWhiteLen = pOEM->wImgWidth * pOEM->dwYmove;

        if (!SpoolWhiteData(pdevobj, dwWhiteLen, FALSE))
            return FALSE;

        pOEM->dwCurCursorY += pOEM->dwYmove;
        pOEM->dwYmove = 0;
    }

    pOEM->dwCurCursorY += dwLen/pOEM->wImgWidth - 1 ;
    pOEM->dwOffset ++ ;

    return MySpool(pdevobj, &(pOEM->sb), pBuf,dwLen);
}


//fill page blanks.
BOOL FillPageRestData(PDEVOBJ pdevobj)
{

    PIBMPDEV    pOEM ;
    DWORD        dwRestHigh ;
    DWORD        dwWhiteLen ;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;
    
    dwRestHigh = pOEM->ptlLogSize.y - pOEM->dwCurCursorY ;

    if(dwRestHigh <= 0)
        return TRUE;

    dwWhiteLen = pOEM->ptlLogSize.x * dwRestHigh;

    return SpoolWhiteData(pdevobj, dwWhiteLen, pOEM->fComp);
}

//not white data
BOOL SendPageData(PDEVOBJ pdevobj, PBYTE pSrcImage, DWORD dwLen)
{
    PIBMPDEV           pOEM;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    return SpoolOutComp(&pOEM->Soc, pdevobj, &pOEM->sb, pSrcImage, dwLen);
}

BOOL SpoolWhiteData(PDEVOBJ pdevobj, DWORD dwWhiteLen, BOOL fComp)
{

    PIBMPDEV    pOEM;
    PBYTE        pWhite ;
    WORD        wCompLen ;
    DWORD        dwTempLen ;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;

    if(dwWhiteLen == 0)
        return TRUE;

    if(dwWhiteLen > MAXIMGSIZE){
        dwTempLen = MAXIMGSIZE ;
    }else{
        dwTempLen = dwWhiteLen ;
    }

    if (!AllocTempBuffer(pOEM, dwTempLen))
        return FALSE;
    pWhite = pOEM->pTempImage;

    ZeroMemory(pWhite, dwTempLen);

    if(fComp == TRUE)
    {
        DWORD dwTemp;

        while (0 < dwWhiteLen) {

            if (MAXIMGSIZE <= dwWhiteLen)
                dwTemp = MAXIMGSIZE;
            else
                dwTemp = dwWhiteLen;

            if (!SpoolOutComp(&pOEM->Soc, pdevobj, &pOEM->sb, pWhite, dwTemp))
                return FALSE;
            dwWhiteLen -= dwTemp;
        }

    }
    else{
        if(dwWhiteLen > MAXIMGSIZE){
            while(dwWhiteLen > MAXIMGSIZE){
                if (!MySpool(pdevobj, &pOEM->sb, pWhite, MAXIMGSIZE))
                    return FALSE;

                dwWhiteLen -= MAXIMGSIZE ;
            }
        }

        if(dwWhiteLen > 0){
            if (!MySpool(pdevobj, &pOEM->sb, pWhite, dwWhiteLen))
                return FALSE;

        }
    }

    return TRUE;
}

BOOL SpoolOutChangedData(PDEVOBJ pdevobj, LPSB lpsb)
{
    PIBMPDEV    pOEM;
    POINTL        ptlDataPos ;
    DWORD        dwFilePos, dwTemp;
    HANDLE        hFile ;
    PBYTE        pSaveFileData ;
    PBYTE        pTemp;
    PBYTE        pTransBuf ;
    DWORD        X, Y;
    DWORD        dwFirstPos ;
    INT h, i, j, k;

    POINTL ptlBand;
    PBYTE pSrc, pDst, pSrcSave;
    DWORD dwBandY, dwImageY, dwImageX;
    BOOL bBlank, bZero;
    BOOL bRet = FALSE;

    pOEM = (PIBMPDEV)pdevobj->pdevOEM;
    hFile = pOEM->sb.hFile ;

    // band size in pixels
    ptlBand.x = pOEM->ptlLogSize.y;
    ptlBand.y = TRANS_BAND_Y_SIZE;

    //�t�@�C���̓ǂݍ��݊J�n�ʒu���v�Z
    // Calculate read start positoin in the file
    ptlDataPos.x = 0 ;
    ptlDataPos.y = pOEM->dwCurCursorY + pOEM->dwOffset ;

    //�c�����A�P�s�̂��������]��
    // Y direction, blank area beneth.
    dwImageX = ((ptlDataPos.y + 7) / 8) * 8;

    // Buffer for loading file data (scan lines for a band)
    pSaveFileData = (PBYTE)MemAlloc((ptlBand.y / 8) * dwImageX);
    if (NULL == pSaveFileData) {
        ERR(("Failed to allocate memory.\n"));
        return FALSE;
    }

    // Buffer for transpositions (one scan line)
    pTransBuf = (PBYTE)MemAlloc((ptlBand.x / 8));
    if (NULL == pTransBuf) {
        ERR(("Failed to allocate memory.\n"));
// #441444: PREFIX: reference NULL pointer.
        goto out;
    }

    //�t�@�C���̓ǂݍ��݈ʒu�w��B
    // Specify read start positoin in the file
    dwFirstPos = pOEM->wImgWidth - 1;

    if (!MySpool(pdevobj,&(pOEM->sbcomp),
                (PBYTE)CMD_BEGIN_PAGE, sizeof(CMD_BEGIN_PAGE)))
        goto out;
    if (!SpoolOutCompStart(&pOEM->Soc))
        goto out;

    dwImageY = pOEM->wImgWidth;

    bBlank = FALSE;
    bZero = FALSE;
    for (X = 0; X < (DWORD)pOEM->ptlLogSize.x / 8; X += dwBandY) {

        //�]���������ɃZ�b�g�B�ǂݔ�΂��B
        // Set blank area, then read skip.
        dwBandY = ptlBand.y / 8;
        if (dwBandY > (DWORD)pOEM->ptlLogSize.x / 8 - X)
            dwBandY = (DWORD)pOEM->ptlLogSize.x / 8 - X;

        // White scanlines.  Currently the trailing ones only,
        // desired to be udpated to include others.

        if (X >= dwImageY) {
            bBlank = TRUE;
        }

        // Output white scanline.
        if (bBlank) {

            if (!bZero) {
                ZeroMemory(pTransBuf, (ptlBand.x / 8));
                bZero = TRUE;
            }

            for (i = 0; i < (INT)dwBandY * 8; i++) {
                if (!SpoolOutComp(&pOEM->Soc, pdevobj, &pOEM->sbcomp,
                    (PBYTE)pTransBuf, (ptlBand.x / 8)))
                    goto out;
            }
            continue;
        }

        // Non-white scanlines.

        pTemp = pSaveFileData ;
        dwFilePos = pOEM->wImgWidth - X - dwBandY;

        //�c�����P�s���t�@�C������ǂݎ��B
        // Read vertial one line from the file.

        for (Y = 0; Y < dwImageX; pTemp += dwBandY, Y++) {

            if (Y >= (DWORD)ptlDataPos.y) {
                ZeroMemory(pTemp, dwBandY);
                continue;
            }

            if(INVALID_SET_FILE_POINTER==SetFilePointer(hFile,dwFilePos,NULL,FILE_BEGIN)){
                 ERR((DLLTEXT("SetFilePointer failed %d\n"),
                     GetLastError()));
// #441442: PREFIX: leaking memory.
                    // return;
                    goto out;
            }

            if (0 == ReadFile(hFile, pTemp, dwBandY, &dwTemp, NULL)
                    || dwTemp > dwBandY) {
                 ERR(("Faild reading data from file. (%d)\n",
                     GetLastError()));
// #441442: PREFIX: leaking memory.
                // return;
                goto out;
            }

            dwFilePos += pOEM->wImgWidth;

        }//End of Y loop

        // Transposition and output dwBandY * 8 scan lines
        for (h = 0; h < (INT)dwBandY; h++) {

            //VERBOSE(("> %d/%d\n", h, dwBandY));

            pSrcSave = pSaveFileData + dwBandY - 1 - h;

            // Transposition and output eight scan lines
            for (j = 0; j < 8; j++) {

                pSrc = pSrcSave;
                pDst = pTransBuf;
                ZeroMemory(pDst, (ptlBand.x / 8));

                // Transposition one scan line

                for (i = 0; i < (INT)(dwImageX / 8); i++){

                    for (k = 0; k < 8; k++) {

                        if (0 != (*pSrc & Mask[7 - j])) {
                            *pDst |= Mask[k];
                        }
                        pSrc += dwBandY;
                    }
                    pDst++;
                }

                // Output one scan line
                if (!SpoolOutComp(&pOEM->Soc, pdevobj, &pOEM->sbcomp,
                    (PBYTE)pTransBuf, (ptlBand.x / 8)))
                    goto out;
            }
        }

    }

    // Mark end of image
    if (!SpoolOutCompEnd(&pOEM->Soc, pdevobj, &pOEM->sbcomp))
        goto out;
    if (!MySpool(pdevobj, &(pOEM->sbcomp),
        (PBYTE)CMD_END_PAGE, sizeof(CMD_END_PAGE)))
        goto out;

    bRet = TRUE;

// #441442: PREFIX: leaking memory.
out:
    if (NULL != pSaveFileData){
        MemFree(pSaveFileData);
    }
    if(NULL != pTransBuf){
        MemFree(pTransBuf);
    }

    return bRet;
}

BOOL
AllocTempBuffer(
    PIBMPDEV pOEM,
    DWORD dwNewBufLen)
{
   if (NULL == pOEM->pTempImage ||
        dwNewBufLen > pOEM->dwTempBufLen) {

        if (NULL != pOEM->pTempImage) {
            MemFree(pOEM->pTempImage);
        }
        pOEM->pTempImage = (PBYTE)MemAlloc(dwNewBufLen);
        if (NULL == pOEM->pTempImage) {
            WARNING(("Failed to allocate memory. (%d)\n",
                GetLastError()));

            pOEM->dwTempBufLen = 0;
            return FALSE;
        }
        pOEM->dwTempBufLen = dwNewBufLen;
    }
    return TRUE;
}

BOOL
SpoolOutCompStart(
    PSOCOMP pSoc)
{
    pSoc->iNRCnt = 0;
    pSoc->iRCnt = 0;
    pSoc->iPrv = -1;

    return TRUE;
}

BOOL
SpoolOutCompEnd(
    PSOCOMP pSoc,
    PDEVOBJ pdevobj,
    LPSB psb)
{
    BYTE jTemp;

    if (0 < pSoc->iNRCnt) {
        jTemp = ((BYTE)pSoc->iNRCnt) - 1;
        if (!MySpool(pdevobj, psb, &jTemp, 1))
            return FALSE;
        if (!MySpool(pdevobj, psb, pSoc->pjNRBuf, pSoc->iNRCnt))
            return FALSE;
        pSoc->iNRCnt = 0;
    }

    if (0 < pSoc->iRCnt) {
        jTemp = (0 - (BYTE)pSoc->iRCnt) + 1;
        if (!MySpool(pdevobj, psb, &jTemp, 1))
            return FALSE;
        if (!MySpool(pdevobj, psb, &pSoc->iPrv, 1))
            return FALSE;
        pSoc->iRCnt = 0;
    }

    return TRUE;
}

BOOL
SpoolOutComp(
    PSOCOMP pSoc,
    PDEVOBJ pdevobj,
    LPSB psb,
    PBYTE pjBuf,
    DWORD dwLen)
{
    BYTE jCur, jTemp;

    while (0 < dwLen--) {

        jCur = *pjBuf++;

        if (pSoc->iPrv == jCur) {

            if (0 < pSoc->iNRCnt) {
                if (1 < pSoc->iNRCnt) {
                    jTemp = ((BYTE)pSoc->iNRCnt - 1) - 1;
                    if (!MySpool(pdevobj, psb, &jTemp, 1))
                        return FALSE;
                    if (!MySpool(pdevobj, psb, pSoc->pjNRBuf, pSoc->iNRCnt - 1))
                        return FALSE;
                }
                pSoc->iNRCnt = 0;
                pSoc->iRCnt = 1;
            }

            pSoc->iRCnt++;

            if (RPEAK == pSoc->iRCnt) {
                jTemp = (0 - (BYTE)pSoc->iRCnt) + 1;
                if (!MySpool(pdevobj, psb, &jTemp, 1))
                    return FALSE;
                if (!MySpool(pdevobj, psb, &jCur, 1))
                    return FALSE;
                pSoc->iRCnt = 0;
            }
        }
        else {

            if (0 < pSoc->iRCnt) {
                jTemp = (0 - (BYTE)pSoc->iRCnt) + 1;
                if (!MySpool(pdevobj, psb, &jTemp, 1))
                    return FALSE;
                if (!MySpool(pdevobj, psb, &pSoc->iPrv, 1))
                    return FALSE;
                pSoc->iRCnt = 0;
            }

            pSoc->pjNRBuf[pSoc->iNRCnt++] = jCur;

            if (NRPEAK == pSoc->iNRCnt) {
                jTemp = ((BYTE)pSoc->iNRCnt) - 1;
                if (!MySpool(pdevobj, psb, &jTemp, 1))
                    return FALSE;
                if (!MySpool(pdevobj, psb, pSoc->pjNRBuf, pSoc->iNRCnt))
                    return FALSE;
                pSoc->iNRCnt = 0;
            }
        }
        pSoc->iPrv = jCur;
    }

    return TRUE;
}

/*++

Routine Name

    ImpersonationToken

Routine Description:

    This routine checks if a token is a primary token or an impersonation 
    token.    
    
Arguments:

    hToken - impersonation token or primary token of the process
    
Return Value:

    TRUE, if the token is an impersonation token
    FALSE, otherwise.
    
--*/
BOOL
ImpersonationToken(
    IN HANDLE hToken
    )
{
    BOOL       bRet = TRUE;
    TOKEN_TYPE eTokenType;
    DWORD      cbNeeded;
    DWORD      LastError;

    //
    // Preserve the last error. Some callers of ImpersonatePrinterClient (which
    // calls ImpersonationToken) rely on the fact that ImpersonatePrinterClient
    // does not alter the last error.
    //
    LastError = GetLastError();
        
    //
    // Get the token type from the thread token.  The token comes 
    // from RevertToPrinterSelf. An impersonation token cannot be 
    // queried, because RevertToPRinterSelf doesn't open it with 
    // TOKEN_QUERY access. That's why we assume that hToken is
    // an impersonation token by default
    //
    if (GetTokenInformation(hToken,
                            TokenType,
                            &eTokenType,
                            sizeof(eTokenType),
                            &cbNeeded))
    {
        bRet = eTokenType == TokenImpersonation;
    }        
    
    SetLastError(LastError);

    return bRet;
}

/*++

Routine Name

    RevertToPrinterSelf

Routine Description:

    This routine will revert to the local system. It returns the token that
    ImpersonatePrinterClient then uses to imersonate the client again. If the
    current thread doesn't impersonate, then the function merely returns the
    primary token of the process. (instead of returning NULL) Thus we honor
    a request for reverting to printer self, even if the thread is not impersonating.
    
Arguments:

    None.
    
Return Value:

    NULL, if the function failed
    HANDLE to token, otherwise.
    
--*/
HANDLE
RevertToPrinterSelf(
    VOID
    )
{
    HANDLE   NewToken, OldToken, cToken;
    BOOL	 Status;

    NewToken = NULL;

    Status = OpenThreadToken(GetCurrentThread(),
							 TOKEN_IMPERSONATE,
							 TRUE,
							 &OldToken);
    if (Status) 
    {
        //
        // We are currently impersonating
        //
		cToken = GetCurrentThread();
        Status = SetThreadToken(&cToken,
								NewToken);       
		if (!Status) {
			return NULL;
		}
    }
	else if (GetLastError() == ERROR_NO_TOKEN)
    {
        //
        // We are not impersonating
        //
        Status = OpenProcessToken(GetCurrentProcess(),
								  TOKEN_QUERY,
								  &OldToken);

		if (!Status) {
			return NULL;
		}
    }
    
    return OldToken;
}

/*++

Routine Name

    ImpersonatePrinterClient

Routine Description:

    This routine attempts to set the passed in hToken as the token for the
    current thread. If hToken is not an impersonation token, then the routine
    will simply close the token.
    
Arguments:

    hToken - impersonation token or primary token of the process
    
Return Value:

    TRUE, if the function succeeds in setting hToken
    FALSE, otherwise.
    
--*/
BOOL
ImpersonatePrinterClient(
    HANDLE  hToken)
{
    BOOL	Status;
	HANDLE	cToken;

    //
    // Check if we have an impersonation token
    //
    if (ImpersonationToken(hToken)) 
    {
		cToken = GetCurrentThread();
        Status = SetThreadToken(&cToken,
								hToken);       

        if (!Status) 
        {
            return FALSE;
        }
    }

    CloseHandle(hToken);

    return TRUE;
}