/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDBGETB
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS  CheckBitmap
 *            prdb_GetSetBitmapBits
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GPIERRORS
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_DOSMEMMGR
#include <os2.h>
#undef INCL_DOSSEMAPHORES
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_GPIERRORS
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_DOSMEMMGR

#define INCL_DDIMISC
#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDICOMFLAGS
#include <pmddi.h>
#undef INCL_DDIMISC
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDICOMFLAGS

#define INCL_GRE_BITMAPS
#include <pmddim.h>
#undef INCL_GRE_BITMAPS

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdconse.h>

#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL

#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdgextf.h>
#include <prdcextf.h>
#include <prdyextf.h>
#include <prdbsize.h>

/*extern PFSRSEM           pBMLockSem;     CON3201 */
extern HMTX              hmtxBMLockSem; /* CON3201 */
/* extern USHORT            prdd_HugeInc;  CON3201 */
extern DVTColorTableType DVTEightColorTable;


extern ULONG CompDeCompBull( ULONG,PBITMAPINFO2, PBYTE,
                             PBITMAPINFO2 *,
                             PBYTE *,
                             lpDCI,
                             ULONG,
                             ULONG);
/******************************************************************************/
/*  FUNCTION: CheckBitmap                                                     */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  hanDC   DcH;        Handle to the DC                                      */
/*  ULONG   ScanStart;  The first line of the source/dest                     */
/*  ULONG   ScanCount;  The number of lines of the source/dest                */
/*  PBYTE   hBitmap;    Bitmap handle for source/dest                         */
/*  lpDCI   DCIData;    DCIData                                               */
/*  PULONG  Count;      The number of lines we can get/set                    */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function does initial checking of the parameters for a GetBitmapBits */
/*  or a SetBitmapBits.  It ensures the bitmap exists and adjusts the area    */
/*  which is to be operated on if it is larger than the bitmap.               */
/******************************************************************************/
pBMListEntry CheckBitmap( hanDC    DcH,
                          ULONG    ScanStart,
                          USHORT   ScanCount,
                          PBYTE    hBitmap,
                          lpDCI    DCIData,
                          PUSHORT  Count )

{
#define TFUNC "CheckBitmap"

    /**************************************************************************/
    /*  Local Variables                                                       */
    /**************************************************************************/
    pBMListEntry  ListEntry;           /* Pointer to a bitmap list entry      */
    ULONG         ulTemp;              /* Holds result of GetDriverInfo       */

    if (hBitmap == FNULL)
    {

        /**********************************************************************/
        /*  The bitmap handle we have been given is NULL so see if we can use */
        /*  the selected bitmap in the DC Instance data.                      */
        /**********************************************************************/
        if (DCIData->DCIDCType != OD_MEMORY)
        {

            /******************************************************************/
            /*  We can't have a selected bitmap unless it is a memory DC.     */
            /*                                                                */
            /*  PD00120 : Changed the return code to PMERR_INCORRECT_DC_TYPE  */
            /*  as this is the one expected, not PMERR_INV_FOR_THIS_DC_TYPE   */
            /******************************************************************/
            LOGERR(TFUNC, "Not memory DC", &DCIData->DCIDCType, 1,
                   PMERR_INCORRECT_DC_TYPE);
            return(FNULL);
        }
/*      if (!((PBYTE)ListEntry = DCIData->DCISelBitmap))              CON3201 */
        if (!(ListEntry = (pBMListEntry)DCIData->DCISelBitmap))
        {

            /******************************************************************/
            /*  We can't pick up a selected bitmap.                           */
            /*                                                                */
            /*  PD00131 : Changed error from PMERR_NO_BITMAP_SELECTED to      */
            /*  PMERR_BITMAP_NOT_SELECTED.                                    */
            /******************************************************************/
            LOGERR(TFUNC, "no selected bitmap",FNULL, 0,
                   PMERR_BITMAP_NOT_SELECTED);
            return(FNULL);
        }
    }
    else
    {

        /**********************************************************************/
        /*  We have been given a bitmap handle so first validate it for this  */
        /*  DC.                                                               */
        /**********************************************************************/
/*      FSRSemEnter(pBMLockSem);                                      CON3201 */
        DosRequestMutexSem(hmtxBMLockSem, SEM_INDEFINITE_WAIT);

/*      if (((LONG)ListEntry =                                        CON3201 */
/*          GetDriverInfo(hBitmap, DI_HBITMAP, (HDC)DcH)) == -1)      CON3201 */
    /* CON3201 - We have to split up the above statement, so we will  CON3201 */
    /*  first check the return code and then assign it to ListEntry   CON3201 */
    /*  if it is OK                                                   CON3201 */
        if ((ulTemp =                                              /* CON3201 */
            GetDriverInfo((LHANDLE)hBitmap, DI_HBITMAP, (HDC)DcH)) == -1) /*CON3201*/
        {

            /******************************************************************/
            /*  Bitmap does not belong to this DC.                            */
            /******************************************************************/
/*          FSRSemLeave(pBMLockSem);                                  CON3201 */
            DosReleaseMutexSem(hmtxBMLockSem);
            LOGERR("prdbCheckBM", "invalid source BM", FNULL, 0,
                   PMERR_INV_HBITMAP);
            return(FNULL);
        }

        /**********************************************************************/
        /*  hBitmap ok so lock it for the duration                            */
        /**********************************************************************/
        /* CON3201 - This is the second part of the call, the GetDriverInfo   */
        /*           returned successfully                                    */
        /**********************************************************************/
        ListEntry = (pBMListEntry)ulTemp;
        ListEntry->BMLocked = TRUE;
/*      FSRSemLeave(pBMLockSem);                                      CON3201 */
        DosReleaseMutexSem(hmtxBMLockSem);
    }

    /**************************************************************************/
    /*  Work out how many scanlines we can set or get.                        */
    /**************************************************************************/
    if (ScanStart >= (ListEntry)->Parms.Height)
    {

        /**********************************************************************/
        /*  The start comes after the end of the source - so we can't return  */
        /*  set/get any lines.                                                */
        /**********************************************************************/
        *Count = 0;
    }
    else
    {

        /**********************************************************************/
        /*  Set Count to the number of lines we can set/get allowing for the  */
        /*  height of the bitmap.                                             */
        /**********************************************************************/
        if (ScanStart + ScanCount > (ListEntry)->Parms.Height)
        {
            *Count = (USHORT)(ListEntry->Parms.Height - ScanStart);
        }
        else
        {
            *Count = (USHORT)ScanCount;
        }
    }

    /**************************************************************************/
    /*  Return the pointer to the bitmap list entry to indicate we validated  */
    /*  it.                                                                   */
    /**************************************************************************/
    return(ListEntry);
}
#undef TFUNC

/******************************************************************************/
/*  Note:                                                                     */
/*                                                                            */
/*  GetBitmapBits transfers data from from a given bitmap to application      */
/*  storage.  It is only valid for a Memory DC.  If the given bitmap handle is*/
/*  null then the currently selected bitmap in the given DC is used (an error */
/*  is returned if there is no currently selected bitmap in the given DC).    */
/*                                                                            */
/*  The application defines the region of the bitmap to be set in terms of a  */
/*  number of scanlines.  Scanlines are numbered downward.  The actual number */
/*  of scanlines for which data is obtained is returned (this may be less than*/
/*  the application requested).                                               */
/*                                                                            */
/*  The application gives the device driver two pointers; the BitmapBits and a*/
/*  BitmapInfoTable with which to interpret these bits.                       */
/*                                                                            */
/*  The bitcount and number of planes in the table have been set by the       */
/*  application; the device driver returns an error if these do not correspond*/
/*  to a standard Winthorn format.                                            */
/*                                                                            */
/*  The device driver sets the width and height in this table; it also sets a */
/*  pointer to a colour table.  This new BitmapInfoTable then defines the     */
/*  meaning of the bits which the device driver places in application storage */
/*                                                                            */
/*  SetBitmapBits transfers data from application storage to the given bitmap.*/
/*  It is only valid for a Memory DC.  If the given bitmap handle is null then*/
/*  the currently selected bitmap in the given DC is used (an error is        */
/*  returned if there is no currently selected bitmap in the given DC).       */
/*                                                                            */
/*  The application defines the region of the bitmap to be set in terms of a  */
/*  number of scanlines.  Scanlines are numbered downward.  The actual number */
/*  of scanlines for which data is set is returned (this may be less than the */
/*  application requested).                                                   */
/*                                                                            */
/*  The application gives the device driver two pointers; the BitmapBits and a*/
/*  BitmapInfoTable with which to interpret these bits.  The device driver    */
/*  returns an error if this does not correspond to a standard Winthorn       */
/*  format.                                                                   */
/*                                                                            */
/*  SetBitmapBits is not subject to clipping.  The draw bit is not tested.    */
/******************************************************************************/

/******************************************************************************/
/*  FUNCTION: prdb_GetSetBitmapBits                                           */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  See "OS/2 Technical Reference: I/O Subsytems and Device Drivers"          */
/*                                                                            */
/*  hanDC        DcH;                                                         */
/*  PBYTE        hBitmap;                                                     */
/*  ULONG        ArgScanStart;                                                */
/*  ULONG        ArgScanCount;                                                */
/*  PBYTE        ArgAddress;                                                  */
/*  PBITMAPINFO  ArgInfo;                                                     */
/*  lpDCI        DCIData;                                                     */
/*  ULONG        FunN;                                                        */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function deals with both GetBitmapBits and SetBitmapBits processing, */
/*  as they both have a large amount of similar parameter checking.  It       */
/*  performs this checking, then uses FunN to decide whether the call is a Get*/
/*  or a Set.  Note that if ArgAddress is not DWORD aligned, as specified in  */
/*  the interface definition, strange and unusual things may happen.          */
/******************************************************************************/
ULONG EXPENTRY prdb_GetSetBitmapBits( hanDC        DcH,
                                      PBYTE        hBitmap,
                                      ULONG        ArgScanStart,
                                      ULONG        ArgScanCount,
                                      PBYTE        ArgAddress,
/* CON3201 - GRE CHANGE  */           PBITMAPINFO2 ArgInfo,
                                      lpDCI        DCIData,
                                      ULONG        FunN )

{
#define TFUNC "GetSetBMBits"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    ULONG         Command;             /* Command part of FunN                */
    USHORT        LineCount;           /* number of scanlines to do           */
    pBMListEntry  ListEntry;           /* Pointer to bitmap list entry        */
    DevRect       BoundsRect;          /* Bounding rectangle for              */
                                       /* scanlines                           */
    PBYTE         ArgBitmap;           /* temperary pointer to bitmap         */
    PBITMAPINFO2  tmpArgInfo;          /* temp pointer to ArgInfo             */
    ULONG         compReturn = 0;          /* return code from CompDeCompBull     */
    ULONG         Compression = 0;
    ULONG         BytesToConvert = 0;

    tmpArgInfo = ArgInfo;
    ArgBitmap = ArgAddress;

    Command = FunN & 0xFFFF0000L;     /* COM3201 - Mask off the lower 16 bits */
    TRACE8(TFUNC, "Command", &Command, 1);
    if (Command & COM_PATH)
    {
        LOGERR(TFUNC, "Invalid in path", FNULL, 0, PMERR_INV_IN_PATH);
        return(ERROR_NEG);
    }
    if (Command & COM_AREA)
    {
        LOGERR(TFUNC, "Invalid in area", FNULL, 0, PMERR_INV_IN_AREA);
        return(ERROR_NEG);
    }

    /**************************************************************************/
    /*  Trace the parameters.                                                 */
    /**************************************************************************/
    TRACE8(TFUNC, "FuncNo",        &FunN, 1);
    TRACE8(TFUNC, "DcH",           &DcH, 1);
    TRACE8(TFUNC, "Info address",  &ArgInfo, 1);
    TRACE8(TFUNC, "Info table",    ArgInfo, 10);
    TRACE8(TFUNC, "Address",       &ArgAddress, 1);
    TRACE8(TFUNC, "Bytes to copy", ArgAddress, 20);
    TRACE8(TFUNC, "Scan count",    &ArgScanCount, 1);
    TRACE8(TFUNC, "Scan start",    &ArgScanStart, 1);
    TRACE8(TFUNC, "DCIData",       &DCIData, 1);

    /**************************************************************************/
    /*  Check that ArgScanCount is a reasonable value                         */
    /**************************************************************************/
    if (ArgScanCount & 0xFFFF0000)
    {

        /**********************************************************************/
        /*  ArgScanCount is invalid.  Log an error and exit.                  */
        /**********************************************************************/
        LOGERR(TFUNC, "Invalid ArgCount", &ArgScanCount, 1,PMERR_INV_LENGTH_OR_COUNT);
        return(ERROR_NEG);
    }

    /**************************************************************************/
    /*  PD00131 : Validate the length field for the ArgInfo structure.  Note  */
    /*  that we need to check against both of the following structure sizes   */
    /*  due to an unbelievably common error in which the app passes in the    */
    /*        size (due to the incredible similarity of the two structures).  */
    /**************************************************************************/
/*****************************************************************************/
/*  CON3201 - GRE change                                                     */
/*  if ((ArgInfo->cbFix != sizeof(BITMAPINFO)) &&                            */
/*      (ArgInfo->cbFix != sizeof(BITMAPINFOHEADER)))                        */
/*****************************************************************************/
    if ((ArgInfo->cbFix < MIN_BITMAPINFO) ||
        (ArgInfo->cbFix > sizeof(BITMAPINFOHEADER2)))

    {
        LOGERR(TFUNC, "invalid BMINFO", FNULL, 0, PMERR_INV_INFO_TABLE);
        return(ERROR_NEG);
    }

    /******************************************************************/
    /* Do entry processing                                            */
    /* done in layer                                                  */
    /******************************************************************/
 /*   if (!prdz_EnterDriver(DCIData))
        return(ERROR_NEG);   */

#ifdef PRD_TIMING
    DEKHOOK0(A,7,49)
#endif

    /**************************************************************************/
    /*  Do the initial checks                                                 */
    /**************************************************************************/
    if ((ListEntry = CheckBitmap(DcH, ArgScanStart, (USHORT)ArgScanCount,
                                 hBitmap, DCIData, &LineCount)) == FNULL)
    {
        TRACE4(TFUNC, "bm check failed", FNULL, 0);
    /*    prdm_LeaveDriver(DCIData);*/
#ifdef PRD_TIMING
    DEKHOOK0(A,7,C9)
#endif
        return(ERROR_NEG);
    }

    /**************************************************************************/
    /*  Return error if requested format is not one of the standard Winthorn  */
    /*  formats                                                               */
    /**************************************************************************/
    if (ArgInfo->cPlanes != 1 ||
        (ArgInfo->cBitCount != 1 && ArgInfo->cBitCount != 4 &&
         ArgInfo->cBitCount != 8 && ArgInfo->cBitCount != 24) )
    {
        LOGERR(TFUNC, "Not standard format", FNULL, 0, PMERR_INV_INFO_TABLE);
        if (hBitmap)
            ListEntry->BMLocked = FALSE;
/*       prdm_LeaveDriver(DCIData);  */
#ifdef PRD_TIMING
    DEKHOOK0(A,7,C9)
#endif
        return(ERROR_NEG);
    }

    /**************************************************************************/
    /*  Validate Starting scan line.  It must lie within the target bitmap    */
    /**************************************************************************/
    if (ArgScanStart >= ListEntry->Parms.Height)
    {
        LOGWARNING(TFUNC, "Invalid scan start", FNULL, 0, PMERR_INV_SCAN_START);
        LineCount = 0;
    }

    /**************************************************************************/
    /*  If no lines are to be set in SetBitmapBits then return now.  For      */
    /*  GetBitmapBits the driver still needs to fill in the colour table -    */
    /*  this is done within prdb_ConvertInttoExt which will return as soon as */
    /*  it has filled in the colour table.                                    */
    /**************************************************************************/
    if ((LineCount == 0) && (LOUSHORT(FunN) == NGreSetBitmapBits))
        goto EXIT_FUNCTION;

    /**************************************************************************/
    /*  Check the FunN to find out whether this is a Get or a Set             */
    /**************************************************************************/
    if ( LOUSHORT(FunN) == NGreGetBitmapBits )
    {
        if (ArgInfo->ulCompression)
        {     /* we have got a compressed bitmap */
            Compression = CBD_COMPRESSION;  /* set the flag */
            if (BytesToConvert = ListEntry->Parms.BytesPerRow * LineCount)
                SafeSSALLOCMEM (&ArgBitmap,BytesToConvert,0);
        }
        /**********************************************************************/
        /*  GetBitmapBits.  Fill in the parameters in ArgInfo from the        */
        /*  ListEntry data.                                                   */
        /*                                                                    */
        /*  PD00423 : Had to change value for cbFix to size of the structure  */
        /*  from constant 0x0C which was incorrect.                           */
        /*                                                                    */
        /*  PD00793 : Use sizeof(BITMAPINFOHEADER), not the BITMAPINFO as     */
        /*  there is a packed array at the end of the BITMAPINFO structure of */
        /*  indeterminate size.                                               */
        /**********************************************************************/
        ArgInfo->cbFix = MIN_BITMAPINFOHEADER2;                    /* CON3201 */
        ArgInfo->cx    = ListEntry->Parms.Width;                   /* CON3201 */
        ArgInfo->cy    = ListEntry->Parms.Height;                  /* CON3201 */

        /**********************************************************************/
        /*  Call ConvertInttoExt to the main work                             */
        /*                                                                    */
        /*  PD00400 : GWD.  Add DCIData to call                               */
        /**********************************************************************/
        prdb_ConvertInttoExt(ListEntry, ArgBitmap, ArgInfo, ArgScanStart,
                             LineCount, DCIData);
        if(Compression && BytesToConvert)
        {
           compReturn = CompDeCompBull (DcH,ArgInfo,ArgBitmap,
                                        &tmpArgInfo,&ArgAddress,DCIData,FunN,
                                        Compression);
           SSFREEMEM(ArgBitmap); /* tmpArgInfo is freed in CompDeCompBull */
           if (compReturn == GPI_ERROR)
               LineCount = ERROR_NEG;
        }
    }
    else
    {
        /**********************************************************************/
        /*  SetBitmapBits.  If bounds determination required then accumulate  */
        /*  bounds.  Note -1 as bounds are inclusive.                         */
        /**********************************************************************/
        if ((Command & COM_BOUND) != 0)
        {
            BoundsRect[0].X = 0;
            BoundsRect[0].Y = (USHORT)ArgScanStart;
            BoundsRect[1].X = (USHORT)ListEntry->Parms.Width - 1;
            BoundsRect[1].Y = (USHORT)ArgScanStart + (USHORT)ArgScanCount - 1;
         /* (VOID)prdg_AddBounds((DevRect far *) BoundsRect, DCIData); */
            (VOID)prdg_AddBounds((DevRect *) BoundsRect, DCIData); /* CON3201 */
        }

        if (ArgInfo->ulCompression)
        {
            Compression = CBD_DECOMPRESSION;
            compReturn = CompDeCompBull (DcH,ArgInfo,ArgAddress,
                                      &tmpArgInfo,&ArgBitmap,DCIData,FunN,
                                                        Compression);
            if (compReturn == GPI_ERROR)
            {
                LineCount = ERROR_NEG;
                goto EXIT_FUNCTION;
            }
        }
        /**********************************************************************/
        /*  Call ConvertExttoInt to the main work                             */
        /*                                                                    */
        /*  PD00400 : GWD.  Add DCIData to call                               */
        /**********************************************************************/
        prdb_ConvertExttoInt(ListEntry, ArgBitmap, tmpArgInfo, ArgScanStart,
                             LineCount, DCIData);
        if (Compression)
        {
            SSFREEMEM (ArgBitmap);
            prdu_memcpy (ArgInfo,tmpArgInfo,sizeof(BITMAPINFOHEADER2) +
                             (2 << ((tmpArgInfo->cBitCount)-1)) * sizeof(RGB2));
            SSFREEMEM (tmpArgInfo);
        }
    }

EXIT_FUNCTION:

    /**************************************************************************/
    /*  if a bitmap handle was supplied then its time to unlock the bitmap    */
    /**************************************************************************/
    if (hBitmap)
        ListEntry->BMLocked = FALSE;

    /**************************************************************************/
    /*  Return number of lines actually set.                                  */
    /**************************************************************************/
/*    prdm_LeaveDriver(DCIData);   */
#ifdef PRD_TIMING
    DEKHOOK0(A,7,C9)
#endif
    return((ULONG)LineCount);
}
#undef TFUNC
