;*DDK*************************************************************************/
;
; 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.;
;*****************************************************************************/
        page    ,132
;/*****************************************************************************
;*
;* SOURCE FILE NAME = BMSUP.ASM
;*
;* DESCRIPTIVE NAME = Bitmap Support.
;*
;*
;* VERSION      V2.0
;*
;* DATE         01/13/88
;*
;* DESCRIPTION  Various functions relating to bitmaps.
;*
;* FUNCTIONS    DeviceCreateBitmap                
;*              DeviceDeleteBitmap                
;*              DeviceSelectBitmap
;*              SetBitmapBits
;*              GetBitmapBits
;*              deselect_bitmap
;*              check_bitmap_info
;*              save_bitmap
;*              alloc_uncomp_buffer     
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   01/13/88                     Written by Walt Moore
;*   03/21/88                     Martin Picha [martinpi]
;*                                Implemented DCR 23453 (use of bitmapinfoheader)
;*   07/13/88                     [bobgru] Changed error returned in case of     
;*                                bitmap dimensions from INV_INFO_TABLE to 
;*                                INV_BITMAP_DIMENSION.  We now check for a valid
;*                                value in bmp_cbFix, and return INV_LENGTH_OR_COUNT 
;*                                if we don't find one.
;*   12/01/91                     ScottL - Ported to 32 bit assembler.
;*   04/29/92                     ScottL fixed PTR SM11885:
;*                                A program called dlg1for.exe was running out 
;*                                of stack space and crashing. We now allocate 
;*                                the bitmap decompression buffer using 
;*                                private_alloc instead of off of the stack.
;*   09/02/92              50403  Fixed problem with Jigsaw using OS2LOGO.BMP
;*   11/25/92                     bmc_int_to_ext called with incorrect parameter
;*
;*****************************************************************************/

        .386
        .MODEL FLAT,SYSCALL
        ASSUME  SS:FLAT, DS:FLAT, CS:FLAT, ES:FLAT
        .xlist

INCL_DDIMISC            equ     1
INCL_GRE_BITMAPS        equ     1
INCL_GPIBITMAPS         equ     1
INCL_GPILOGCOLORTABLE   equ     1
INCL_DEV                equ     1
INCL_GRE_DEVSUPPORT     equ     1       ;for off_ConvertBitmapData
INCL_DDICOMFLAGS        equ     1
        include pmgre.inc
DINCL_BITMAP            equ     1
DINCL_ENABLE            equ     1
DINCL_DEVBITMAP         equ     1
        include driver.inc
        include extern.inc
        include protos.inc
        include assert.mac
        .list

NGreConvertBitmapData equ  0000420Eh

InnerGre32Entry9  PROTO @Gre32Entry9

MAX_REASONABLE_FMT      equ     24      ;Max format user can request
MAX_BITMAP_DIMENSION    equ     7fffh   ;32K

.DATA
        include bmi2.inc

bmp2_check_point    label   byte
        db      dcb_bogus_length_or_count - dcb_bogus_length_or_count
        db      dcb_cBitCount - dcb_bogus_length_or_count
        db      dcb_ulCompression - dcb_bogus_length_or_count
        db      dcb_cbImage - dcb_bogus_length_or_count
        db      dcb_cxResolution - dcb_bogus_length_or_count
        db      dcb_cyResolution - dcb_bogus_length_or_count
        db      dcb_cclrUsed - dcb_bogus_length_or_count
        db      dcb_cclrImportant - dcb_bogus_length_or_count
        db      dcb_usUnits - dcb_bogus_length_or_count
        db      dcb_usReserved - dcb_bogus_length_or_count
        db      dcb_usRecording - dcb_bogus_length_or_count
        db      dcb_usRendering - dcb_bogus_length_or_count
        db      dcb_cSize1 - dcb_bogus_length_or_count
        db      dcb_cSize2 - dcb_bogus_length_or_count
        db      dcb_ulColorEncoding - dcb_bogus_length_or_count
        db      dcb_ulIdentifier - dcb_bogus_length_or_count

bmi2_check_point    label   byte
        db      cbmi_invalid_format - cbmi_ulIdentifier
        db      cbmi_cBitCount - cbmi_ulIdentifier
        db      cbmi_ulCompression - cbmi_ulIdentifier
        db      cbmi_cbImage - cbmi_ulIdentifier
        db      cbmi_cxResolution - cbmi_ulIdentifier
        db      cbmi_cyResolution - cbmi_ulIdentifier
        db      cbmi_cclrUsed - cbmi_ulIdentifier
        db      cbmi_cclrImportant - cbmi_ulIdentifier
        db      cbmi_usUnits - cbmi_ulIdentifier
        db      cbmi_usReserved - cbmi_ulIdentifier
        db      cbmi_usRecording - cbmi_ulIdentifier
        db      cbmi_usRendering - cbmi_ulIdentifier
        db      cbmi_cSize1 - cbmi_ulIdentifier
        db      cbmi_cSize2 - cbmi_ulIdentifier
        db      cbmi_ulColorEncoding - cbmi_ulIdentifier
        db      cbmi_ulIdentifier - cbmi_ulIdentifier

page

        WAS_GLOBAL_ALLOC MACRO
        INVOKE private_alloc
        ENDM
        WAS_GLOBAL_FREE MACRO
        INVOKE private_free
        ENDM

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceCreateBitmap
;*
;* DESCRIPTION   = Asks the device driver to create a bitmap.  The device 
;*                 driver may create it in system RAM, or in its own hardware.  
;*                 The bitmap may be kept in any format.  The device driver 
;*                 returns a handle for the bitmap. The handle is private 
;*                 to the device and will be used only to identify
;*                 the bitmap in calls to the driver.
;*
;*                 Optionally, the device may be requested to initialize the bitmap.
;*                 
;*                 Registers Destroyed:
;*                   AX,BX,CX,DX,ES,FLAGS
;*                 Registers Preserved:
;*                   SI,DI,DS,BP
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = Handle to bitmap
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;*
;**************************************************************************/

.CODE

ALIGN 4
DeviceCreateBitmap      PROC SYSCALL USES EDI ESI EBX,
        hdc             :DWORD,
        lpInfoHdr       :DWORD,
        Usage           :DWORD,
        lpBits          :DWORD,
        lpInitInfo      :DWORD,
        pddc            :DWORD,
        FunN            :DWORD

;/*
;** Create the bitmap header here, and indicate there was a conversion
;*/

        LOCAL  bmTemp:BITMAP            
        LOCAL  bmiDecomp[BITMAPINFOHEADER2.bmp2_ulCompression + (256*sizeof RGB2)]:CHAR
        LOCAL  fConvBM:BYTE                

        DCBF_CONV_BM    equ     00000001b   

        DebugMsg <DeviceCreateBitmap DISPATCH SEL>
;/*
;** GPI defines the usage bit as CBM_INIT wheras we use BITMAP_USAGE_TRANSLATE
;** everywhere.
;*/

        .errnz  BITMAP_USAGE_TRANSLATE - CBM_INIT

        ddc?    pddc

        cld
        mov     fConvBM,0               ;clear the flag
                                        ;Initialize the temporary bitmap
                                        ; structure
        lea     edi,bmTemp.bm_sd
        mov     eax,SURFACE_IDENT
        mov     [edi].SURFACE.sd_usId,eax
        mov     eax,INVALID_ADDRESS     ;Make surface pointer be bogus
        mov     [edi].SURFACE.sd_npsd,eax ; It will have to be fixed up
                                        ;  once real memory is allocated
        mov     ax,SD_NONNULL           ;Assume cx <> 0 and cy <> 0
                                        ;  until we find out otherwise
        mov     WORD PTR [edi].SURFACE.sd_fb,ax

        .errnz  SURFACE.sd_fbAccel-SURFACE.sd_fb-1
        .errnz  (sizeof SURFACE.sd_fb)-1
        .errnz  (sizeof SURFACE.sd_fbAccel)-1

        ; just in case the struct is not packed!

        lea     edi,bmTemp.bm_sd.sd_cx
        mov     eax,0
        mov     ecx,((sizeof BITMAP) - BITMAP.bm_sd.sd_cx)/4    ;We already set the first few

        .errnz  (sizeof BITMAP) and 3   ;Must be a word multiple
        rep     stosd
        mov     eax,INVALID_ADDRESS
        mov     bmTemp.bm_sd.sd_pBits,eax
        mov     bmTemp.bm_hddc,eax      ;Unowned bitmap


;/*
;** Validation of passed parameters:
;**
;** Anything less than 0 for planes or bits-per-pixel is considered
;** an error.  Anything greater than a reasonable number is considered
;** an error.  0 for planes or bits-per-pixel will be mapped to our
;** favored format (monochrome or color depending on the display).
;**
;** If the passed color format is not one of our internal bitmap
;** formats, map it to the nearest format.  We will map anything
;** which isn't a monochrome bitmap to our four plane format (except
;** 0,0 as noted above).
;**
;** The maximum allowed extent of the bitmap is 32K-1.
;*/

        mov     edi,lpInfoHdr


        ASSUME  edi:PTR BITMAPINFOHEADER2


        mov     esi,[edi].bmp2_cbFix
        cmp     esi,SIZEOF BITMAPINFOHEADER
        jne     dcb_new_header


        ASSUME  edi:PTR BITMAPINFOHEADER


        cmp     [edi].bmp_cPlanes,MAX_REASONABLE_FMT
        ja      dcb_bogus_format
        cmp     [edi].bmp_cBitCount,MAX_REASONABLE_FMT
        ja      dcb_bogus_format
        cmp     [edi].bmp_cx,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        cmp     [edi].bmp_cy,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        movzx   eax,[edi].bmp_cPlanes
        movzx   ebx,[edi].bmp_cBitCount
        movzx   esi,[edi].bmp_cx
        movzx   edi,[edi].bmp_cy
        jmp     dcb_header_check_done
ALIGN 4

dcb_bogus_dimension::
        mov     eax,PMERR_INV_BITMAP_DIMENSION
        jmp     dcb_log_error
ALIGN 4
dcb_bogus_length_or_count::
        mov     eax,PMERR_INV_LENGTH_OR_COUNT
        jmp     dcb_log_error
ALIGN 4
dcb_bogus_format::
        mov     eax,PMERR_INV_INFO_TABLE
        jmp     dcb_log_error
ALIGN 4

dcb_new_header::
        cmp     esi,SIZE BITMAPINFOHEADER2
        ja      dcb_bogus_length_or_count
        je      dcb_ulIdentifier
        shr     esi,1
        jc      dcb_bogus_format
        add     esi,OFFSET ok_cbFix
        movzx   esi,BYTE PTR [esi]
        add     esi,OFFSET bmp2_check_point
        movzx   esi,BYTE PTR [esi]
        add     esi,OFFSET dcb_bogus_length_or_count
        jmp     esi
ALIGN 4
dcb_ulIdentifier::
dcb_ulColorEncoding::

        ASSUME  edi:PTR BITMAPINFOHEADER2


        cmp     [edi].bmp2_ulColorEncoding,BCE_RGB
        je      dcb_cSize1
        cmp     [edi].bmp2_ulColorEncoding,BCE_PALETTE
        jne     dcb_bogus_format

dcb_cSize1::
dcb_cSize2::
dcb_usRendering::
        cmp     [edi].bmp2_usRendering,BRH_NOTHALFTONED
        jne     dcb_bogus_format
dcb_usRecording::
        cmp     [edi].bmp2_usRecording,BRA_BOTTOMUP
        jne     dcb_bogus_format
dcb_usReserved::
        cmp     [edi].bmp2_usReserved,0
        jne     dcb_bogus_format
dcb_usUnits::
        cmp     [edi].bmp2_usUnits,BRU_METRIC
        jne     dcb_bogus_format
dcb_cclrImportant::
        mov     cx,[edi].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
        cmp     [edi].bmp2_cclrImportant,eax
        ja      dcb_bogus_format
        jmp     dcb_computed_max_colors_already
ALIGN 4
dcb_cclrUsed::
        mov     cx,[edi].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
dcb_computed_max_colors_already::
        cmp     [edi].bmp2_cclrUsed,eax
        ja      dcb_bogus_format
dcb_cyResolution::
dcb_cxResolution::
dcb_cbImage::
        cmp     [edi].bmp2_ulCompression,BCA_UNCOMP
        je      dcb_cBitCount
        cmp     [edi].bmp2_ulCompression,BCA_RLE24
        jg      dcb_bogus_format
        cmp     [edi].bmp2_cbImage,0
        jne     dcb_cBitCount
        jmp     dcb_bogus_format
ALIGN 4
dcb_ulCompression::
        cmp     [edi].bmp2_ulCompression,BCA_UNCOMP
        jne     dcb_bogus_format
dcb_cBitCount::
        cmp     [edi].bmp2_cPlanes,MAX_REASONABLE_FMT
        ja      dcb_bogus_format
        cmp     [edi].bmp2_cBitCount,MAX_REASONABLE_FMT
        ja      dcb_bogus_format
        cmp     [edi].bmp2_cx,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        cmp     [edi].bmp2_cy,MAX_BITMAP_DIMENSION
        ja      dcb_bogus_dimension           ;Height and width must be < 32K
        movzx   eax,[edi].bmp2_cPlanes
        movzx   ebx,[edi].bmp2_cBitCount
        mov     esi,[edi].bmp2_cx
        mov     edi,[edi].bmp2_cy

        ASSUME  edi:NOTHING

dcb_header_check_done:
        mov     bmTemp.bm_sd.sd_cx,esi
        mov     bmTemp.bm_sd.sd_cy,edi
        or      esi,esi                   ; check x dimension


        jle     dcb_bogus_dimension    

        or      edi,edi                   ; check y dimension

        jle     dcb_bogus_dimension


;/*
;** The format looks good.  If the translate option is set, then make sure
;** the bits are in a format we can deal with. If not, we won't attempt to
;** create the bitmap.  If the format is valid, then translating the bits
;** cannot fail and we won't have to worry about backing out of the code
;** once the bitmap is allocated.
;*/

dcb_good_format:
        test    WORD PTR Usage[0],BITMAP_USAGE_TRANSLATE
        jz      dcb_good_translate_data
        push    eax
        push    ebx
        push    esi
        mov     ebx,lpInitInfo
        mov     ecx,1                  ; signal to check all entered fields
        INVOKE  check_bitmap_info
        pop     esi
        pop     ebx
        pop     eax
        or      ecx,ecx
        jz      dcb_bogus_format        ;Unknown format for the bits

;/*
;** There's still a possibility of error, if the color encoding is BCE_PALETTE
;** but there isn't a palette selected into the DC (whether or not the bitmap
;** is selected into the DC).
;*/

        push    ebx
        mov     ebx,lpInitInfo

        ASSUME  ebx:PTR BITMAPINFO2

        cmp     [ebx].bmi2_cbFix,BITMAPINFO2.bmi2_ulColorEncoding
        jbe     dcb_color_encoding_ok
        cmp     [ebx].bmi2_ulColorEncoding,BCE_PALETTE
        jne     dcb_color_encoding_ok

;/*
;** The color encoding is BCE_PALETTE.  If the DC doesn't have a palette
;** selected, then return an error.
;*/


        ASSUME  ebx:PDDC

        mov     ebx,pddc

        test    [ebx].ddc_fbClrTbl,DDC_PALETTE
        jnz     dcb_color_encoding_ok
        mov     ecx,0
dcb_color_encoding_ok:
        pop     ebx
        or      ecx,ecx
        jz      dcb_bogus_format        ;Unknown format for the bits

dcb_good_translate_data:

;/*
;** Get a pointer to the parameter block used for color format and
;** computing memory requirements:
;*/

        mov     ah,bl                   ;AH = Bitcount, AL = planes
        mov     ebx,pbmcDev

        or      al,al                   ;Device's format if either
        jz      dcb_have_data_table     ;  bitcount or planes is 0
        or      ah,ah
        jz      dcb_have_data_table
        mov     ebx,pbmcMono

        cmp     ax,0101h
        je      dcb_have_data_table     ;1,1 - Monochrome
        mov     ebx,pbmcColor           ;?,? - Color

dcb_have_data_table:

;/*
;** If this is a null bitmap, we had to come this far to pick up the color
;** format just in case they try a GetBitmapBits on it.  We can skip the
;** memory calculation for a null bitmap.
;**
;** Currently:
;**
;**       EBX --> bitmap parameter table
;**       ESI = width in pels    (guaranteed < 32K)
;**       EDI = height in scans  (guaranteed < 32K)
;*/


        ASSUME  ebx:PBMC


        mov     al,[ebx].bmc_fbColor
        or      bmTemp.bm_sd.sd_fb,al   ;Flag as color if format is color
        test    bmTemp.bm_sd.sd_fb,SD_NONNULL
        jnz     dcb_os2_alloc   ;Go allocate memory
        jmp     dcb_os2_alloc_ok        ;No global memory needed
ALIGN 4

;/*
;** Compute the size of a single scan of the bitmap, and the size of all
;** planes of a single scan.
;*/

        public  dcb_os2_alloc
dcb_os2_alloc::
        mov     ecx,0
        mov     cl,[ebx].bmc_cRound     ;Round to a dword multiple
        add     esi,ecx
        not     ecx
        and     esi,ecx
        mov     cl,[ebx].bmc_cShr
        shr     esi,cl
        mov     bmTemp.bm_sd.sd_cbScan,esi
        mov     eax,0
        mov     al,[ebx].bmc_cPlanes
        mul     esi
        mov     esi,eax
        mov     bmTemp.bm_sd.sd_dScan,eax

;/*
;** Compute the total amount of memory required for the bitmap.  Our hope
;** is that with a single quick multiply we will determine that it isn't
;** a huge bitmap.
;*/

        mov     ecx,0                   ;Want to end up with size in DX:AX
        mul     edi                     ;result in EDX:EAX
dcb_have_size:

;/*
;** Because of a pipeline problem in Bitblt, it can try to access one extra
;** double word.   We'll allocate an extra dword on the end of the bitmap
;** to help prevent the GP-Fault.  Also an extra one at the beginning.
;*/
        or      eax,eax
        jz      @F
        add     eax,SIZE_DWORD+SIZE_DWORD

@@:

        mov     bmTemp.bm_sd.sd_pBits,SIZE_DWORD

dcb_heap_alloc:
        push    eax
        INVOKE  AllocMem
        pop     ebx
        jecxz   dcb_no_memory   ;SEL

        add     bmTemp.bm_sd.sd_pBits,eax

        or      bmTemp.bm_sd.sd_fb,SD_HEAPBITS  ;Remember that it is from heap
        jmp     dcb_os2_alloc_ok
ALIGN 4

;/*
;** The local memory allocation failed.  Free the global memory and return
;** the error to the caller.  If the global alloc failed or the bitmap is
;** NULL, the selector will be INVALID_SEL.
;*/

dcb_cbm_fail:
        mov     ecx,lpBits              ;selector of decomp. bits in lpBits.hi
        INVOKE   private_free

dcb_free_bm:
        xchg    esi,edi                   ;move hbm to SI
        INVOKE    free_bm

dcb_free_global_mem:
        test    bmTemp.bm_sd.sd_fb,SD_HEAPBITS
        jz      dcb_free_global

dcb_free_heap:
        mov     eax,bmTemp.bm_sd.sd_pBits

        sub     eax,SIZE_DWORD

        INVOKE    FreeMem
        jmp     dcb_no_memory
ALIGN 4

dcb_free_global:
        mov     ecx,bmTemp.bm_sd.sd_pBits    ;If NULL bitmap, then the
        cmp     ecx,INVALID_ADDRESS
        jz      dcb_no_memory
        WAS_GLOBAL_FREE

dcb_no_memory:
        test    fConvBM,DCBF_CONV_BM
        jnz     dcb_error_exit          ;ConvertBitmapData has its own log error
        mov     eax,PMERR_INSUFFICIENT_MEMORY

dcb_log_error:
        save_error_code

dcb_error_exit:
        mov     eax,0
        jmp     dcb_we_go_home_now
ALIGN 4


;/*
;** We're half way home.  The global allocation was successful.  Now
;** allocate space for the local bitmap information in our heap and
;** copy the bits into it.
;*/

dcb_os2_alloc_ok:
        INVOKE  alloc_bm                ;Allocate the bitmap header
        jecxz   dcb_free_global_mem     ;Allocation failed
        mov     edi,eax                 ;--> the real bitmap in our DS
        lea     esi,bmTemp

        ASSUME  esi:PTR BITMAP
        ASSUME  edi:PTR BITMAP

        mov     ecx,(sizeof BITMAP)/4
        .errnz  (sizeof BITMAP) and 3
        rep     movsd

        sub     edi,sizeof BITMAP               ;--> back to the bitmap
        mov     [edi].bm_sd.sd_npsd,edi         ;Set surface pointer

;/*
;** We now have a complete bitmap structure, fully valid, in our DS.
;** Now initialize the bitmap if there were bits passed in.
;*/

        test    WORD PTR Usage[0],BITMAP_USAGE_TRANSLATE
        jz      dcb_initialize_done

;/*
;** We have to check whether the bits is in a compressed form. If so, we
;** have to decompress it prior to the translation.
;/*

        mov     ebx,lpInitInfo

        ASSUME  ebx:PTR BITMAPINFOHEADER2

        .errnz  BITMAPINFOHEADER2.bmp2_cbFix
        .errnz  BITMAPINFOHEADER2.bmp2_cx-BITMAPINFOHEADER2.bmp2_cbFix-4
        .errnz  BITMAPINFOHEADER2.bmp2_cy-BITMAPINFOHEADER2.bmp2_cx-4
        .errnz  BITMAPINFOHEADER2.bmp2_cPlanes-BITMAPINFOHEADER2.bmp2_cy-4
        .errnz  BITMAPINFOHEADER2.bmp2_cBitCount-BITMAPINFOHEADER2.bmp2_cPlanes-2
        .errnz  BITMAPINFOHEADER2.bmp2_ulCompression-BITMAPINFOHEADER2.bmp2_cBitCount-2
        .errnz  BITMAPINFOHEADER2.bmp2_cbImage-BITMAPINFOHEADER2.bmp2_ulCompression-4
        .errnz  BITMAPINFOHEADER2.bmp2_cxResolution-BITMAPINFOHEADER2.bmp2_cbImage-4

        cmp     [ebx].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_cxResolution
        jb      dcb_translate_bits      ;compression not supported in old Info
        cmp     [ebx].bmp2_ulCompression,BCA_UNCOMP
        je      dcb_translate_bits      ;not a compressed bits

dcb_decompress_bits:

;/*
;** pass in:
;**  EBX->bitmapinfo struct
;** returns:
;**  EAX->allocated buffer
;**  ECX=size in bytes
;** error return:
;**  ECX=0
;*/
        INVOKE    alloc_uncomp_buffer     ;allocate a temporary buffer
        or      ecx,ecx
        jz      dcb_free_bm             ;ECX = 0 if fails to allocate one
        xchg    lpBits,eax
                                     ;make EAX    => compressed   bits buffer
                                     ;     lpBits => uncompressed bits buffer
        or      fConvBM,DCBF_CONV_BM    ;we will convert this bitmap

;/*
;** we want to duplicate the bitmapinfo structure from bmp2_cx to bmp2_cBitCount
;** fields
;*/

        push    edi                      ;save near ptr to surface
        lea     ebx,bmiDecomp            ;EBX => local bitmap info
        mov     edi,ebx                  ;EDI => local bitmap info
        mov     esi,lpInitInfo
        mov     ecx,BITMAPINFOHEADER2.bmp2_ulCompression
        shr     ecx,2

        .errnz  BITMAPINFOHEADER2.bmp2_ulCompression and 3

        rep     movsd                   ;we need information

                                        ;set size up to bmp2_cBitCount
        mov     [ebx].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_ulCompression
        pop     edi                     ;EDI => surface

        mov     ecx,0

        mov     edx,eax

        INVOKE  InnerGre32Entry9,
                hdc,
                CBD_DECOMPRESSION,
                0,
                lpInitInfo,
                edx,
                ebx,
                lpBits,
                0,
                NGreConvertBitmapData

        or      eax,eax         ;returns 0 if failed
        jz      dcb_cbm_fail


dcb_translate_bits:

        INVOKE  bmc_ext_to_int,
                edi,                    ; Bitmap
                lpInitInfo,             ; -> Pointer to info block
                lpBits,                 ; -> buffer of source bits
                [edi].bm_sd.sd_cy,      ; Number of scans to copy
                0,                      ; First scan to copy
                pddc                    ; 

;/*
;** Returns:
;**       EAX = # of scanlines translated
;** Error Returns:
;**       EAX = -1
;*/

ifdef FIREWALLS

;/*
;** Since we validated the format of the incoming bits, and we set the
;** start scan and the scan count, this should never have failed.
;**
;** Return count must match the number of scans we passed in
;*/

        cmp     eax,[edi].bm_sd.sd_cy
        je      @F
dcb_set_failed:
        rip     text,<DeviceCreateBitmap - Setting bits should not have failed>
@@:
endif

;/*
;** Now we can free the temporary decompressed buffer, if we did conversion.
;*/

        test    fConvBM,DCBF_CONV_BM    ;did we have a conversion?
        jz      dcb_initialize_done
        mov     ecx,lpBits              ;selector in lpBits.sel
        INVOKE  private_free

dcb_initialize_done:
        xchg    eax,edi                 ;was DX:AX - handle to bitmap
dcb_we_go_home_now:
        DebugMsg <Leaving DeviceCreateBitmap DISPATCH SEL>
        fw_zero <ecx>
        ret
DeviceCreateBitmap ENDP
page

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceDeleteBitmap
;*
;* DESCRIPTION   = Asks the device driver to delete a bitmap that it created.  
;*                 The given handle is the one returned from DeviceCreateBitmap.
;*                 Optionally, the device may be asked to translate the bitmap
;*                 to a standard format before deleting it.
;*
;*                 Registers Preserved:
;*                   SI,DI,DS,BP
;*                 Registers Destroyed:
;*                   AX,BX,CX,DX,ES,FLAGS
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;*
;**************************************************************************/

ALIGN 4
DeviceDeleteBitmap      PROC SYSCALL USES edi esi EBX,
        hdc             :DWORD,
        dhBitmap        :DWORD,
        lpReturns       :DWORD,
        Usage           :DWORD,
        pddc            :DWORD,
        FunN            :DWORD

        LOCAL   selBits:DWORD           ;Selector for returned bits
        LOCAL   selInfo:DWORD           ;Selector for return info table
        LOCAL   npInfoData:DWORD        ;Data for generating BITMAPINFO

        DebugMsg <DeviceDeleteBitmap DISPATCH SEL>
        cld
                                        ; do this to prevent two
                                        ; people from deleting the same
        INVOKE  enter_driver_sem        ; bitmap at the same time
        jc      ddb_exit_no_lock        ; DX:AX = 0 on error

ifdef FIREWALLS

;/*
;** Make sure the bitmap belongs to us.  If not, the engine had an error
;*/

        mov     ebx,dhBitmap

        ASSUME  ebx:PTR BITMAP

        cmp     [ebx].bm_sd.sd_usId,SURFACE_IDENT
        jne     ddb_bad_handle
        test    [ebx].bm_sd.sd_fb,SD_DEVICE
        jnz     ddb_bad_handle

;/*
;** The Engine should never allow us to delete a bitmap which is currently
;** selected into a ddc.  This is an Engine error if it occurs.
;*/

        cmp     [ebx].bm_hddc,INVALID_ADDRESS ;Selected into an hDC?
        jne     ddc_bitmap_selected     ;  (we also firewall ourselves
        cmp     [ebx].bm_cSelect,0      ;  here also by checking both
        je      ddc_bitmap_free_agent   ;  fields we maintain).

ddc_bitmap_selected:
        rip     text,<DeviceDeleteBitmap - Bitmap currently selected into a ddc>
        mov     eax,0
        jmp     ddb_we_be_gone
ALIGN 4

ddb_bad_handle:
        rip     text,<DeviceDeleteBitmap - Invalid bitmap or bitmap handle>
        mov     eax,0
        jmp     ddb_we_be_gone
ALIGN 4

ddb_bits_selector_bad:
        rip     text,<DeviceDeleteBitmap - selector to bits is null/not null>
        mov     eax,0
        jmp     ddb_we_be_gone
ALIGN 4

;/*
;** As an added FIREWALL, make sure that we have a handle to bits if
;** the bitmap is non-null, and make sure there is no handle if the
;** bitmap is supposed to be null.
;*/

ddc_bitmap_free_agent:
        mov     ecx,[ebx].bm_sd.sd_pBits  ;Set ECX=0 if NULL
        inc     ecx
        .ERRNZ  INVALID_ADDRESS+1
        test    [ebx].bm_sd.sd_fb,SD_NONNULL
        jnz     ddb_want_selector
        jecxz   ddc_selector_is_ok
        mov     ecx,0
ddb_want_selector:
        jecxz   ddb_bits_selector_bad
ddc_selector_is_ok:
endif   ; FIREWALLS


;/*
;** If the translate option is set, then enough global memory to hold
;** both the bitmap and the information table must be allocated and the
;** bitmap translated into it.  If no memory exists then return an error.
;*/

        mov     esi,dhBitmap
        test    WORD PTR Usage[0],BITMAP_USAGE_TRANSLATE
        jz      v_ddb_xlate_done_if_needed
        mov     selBits,0
        test    [esi].bm_sd.sd_fb,SD_NONNULL
        jz      ddb_alloc_info_seg      ;Null bitmap, no global mem needed

;/*
;** The maximum memory needed will be (sd_dScan * sd_cy).  For packed-
;** pixel formats, since we allocated to a double word boundary, this
;** will be an exact fit.  For planer formats, there will be some slop
;** in this calculation, a maximum of (sd_cy * (#planes-1)) bytes.  It
;** makes life easier to just ignore this slop.
;*/

        mov     eax,[esi].bm_sd.sd_dScan
                                        ;mul: EDX:EAX <- EAX * SRC
        mul     [esi].bm_sd.sd_cy
        lea     ebx,selBits             ;Selector will be at [EBX]
        mov     ecx,0
        WAS_GLOBAL_ALLOC
        or      ecx,ecx
        jnz     ddb_no_memory           ;Assume no memory for bitmap

ddb_alloc_info_seg:
        mov     edi,pbmcColor

        test    [esi].bm_sd.sd_fb,SD_COLOR
        jnz     ddb_its_color
        mov     edi,pbmcMono

ddb_its_color:

        ASSUME  edi:PBMC

        mov     eax,[edi].bmc_cbInfo
        lea     ebx,selInfo             ;Allocate info segment
        mov     ecx,0
        WAS_GLOBAL_ALLOC
        jecxz   ddb_have_all_memory
        mov     ecx,selBits             ;Don't free bits memory if it
        jecxz   ddb_no_memory           ;  wasn't allocate
        WAS_GLOBAL_FREE


ddb_no_memory:
        mov     eax,PMERR_INSUFFICIENT_MEMORY

ddb_log_error:
        save_error_code
        mov     eax,0
        jmp     ddb_we_be_gone
ALIGN 4

v_ddb_xlate_done_if_needed:
        jmp     ddb_xlate_done_if_needed
ALIGN 4

;/*
;** We have memory for both the BITMAPINFO structure and for the bits.
;** Set up and call the internal-to-external conversion routine.  We
;** must explicitly request a format for the bits to be returned in.
;** This will be either mono or color based on the bitmap format.
;** We must also return the two pointers to the Engine.
;*/

ddb_have_all_memory:
        movzx   edx,[edi].bmc_cBitCount

        cld                             ;Fill in the delete/return structure

        ASSUME  edi:NOTHING

        mov     edi,lpReturns
        mov     ebx,selInfo
        mov     [edi].DELETERETURN.dr_pInfo,ebx
        mov     eax,selBits
        mov     [edi].DELETERETURN.dr_pBits,eax


        ASSUME  ebx:PTR BITMAPINFO2

        mov     [ebx].bmi2_cbFix,16
        .errnz  BITMAPINFO2.bmi2_cBitCount + (SIZEOF BITMAPINFO2.bmi2_cBitCount) - 16
        mov     [ebx].bmi2_cPlanes,1    ;Always 1 plane
        mov     [ebx].bmi2_cBitCount,dx

;/*
;** The scan count depends on whether or not this is a null bitmap
;*/
        mov     ecx,0                  ;put scans to translate into CX

        ASSUME  esi:PTR BITMAP

        test    [esi].bm_sd.sd_fb,SD_NONNULL
        jz      ddb_xlate_have_scan_count
        mov     ecx,[esi].bm_sd.sd_cy
ddb_xlate_have_scan_count:

;/*
;**       mov     edi,pddc        ;Removed: SEL 2-18
;**       mov     edx,eax
;** EBX = selInfo
;** ECX = number of scans
;** EDX = selBits
;** ESI = bitmap
;** EDI = pddc
;*/

ifndef JFIX        ;IBMJ
        INVOKE  bmc_int_to_ext,
                esi,                    ; Bitmap
                ebx,                    ; -> Pointer to info block ;SEL 2-19 swapped
                eax,                    ; -> buffer of source bits ;SEL 2-19 these 2
                ecx,                    ; Number of scans to copy
                0,                      ; First scan to copy
                0                       ;Used by some drivers, but not EGA
else         ;IBMJ
        INVOKE  bmc_int_to_ext,
                esi,                    ; Bitmap
                ebx,                    ; -> Pointer to info block
                eax,                    ; -> buffer of source bits
                ecx,                    ; Number of scans to copy
                0,                      ; First scan to copy
                pddc                    ; SL added 12-11-91
endif         ;IBMJ

ifdef FIREWALLS
        mov     ecx,0                  ;put scans to translate into CX
        test    [esi].bm_sd.sd_fb,SD_NONNULL
        jz      @F
        mov     ecx,[esi].bm_sd.sd_cy
@@:

;/*
;** Since we prepared all the parameters to the conversion routine, the
;** call should never fail. Return count must match the number
;** of scans we passed in
;*/

        cmp     eax,ecx
        je      @F
ddb_set_failed:
        rip     text,<DeviceDeleteBitmap - Getting bits should not have failed>
@@:
endif

;/*
;** Any translation has been performed.  Now try and free the bitmap.
;** We've FIREWALLed the bitmap being selected, so we don't need to
;** check that.  We can assume it is now a free agent.
;**
;*/

ddb_xlate_done_if_needed:
        test    [esi].bm_sd.sd_fb,SD_HEAPBITS
        jz      ddb_global_free

ddb_heap_free:
        mov     eax,[esi].bm_sd.sd_pBits

        sub     eax,SIZE_DWORD

        INVOKE  FreeMem
        jmp     ddb_free_header
ALIGN 4

ddb_global_free:
        mov     ecx,[esi].bm_sd.sd_pBits  ;If no pointer, don't free it
        inc     ecx
        .ERRNZ  INVALID_ADDRESS+1
        jz      ddb_free_header
        dec     ecx
        WAS_GLOBAL_FREE
ddb_free_header:
        INVOKE  free_bm                 ;Takes handle in SI
        mov     eax,1

ddb_we_be_gone:
        INVOKE  leave_driver
ddb_exit_no_lock:
        fw_zero <ecx>
        ret
DeviceDeleteBitmap ENDP
page

;/***************************************************************************
;*
;* FUNCTION NAME = DeviceSelectBitmap
;*
;* DESCRIPTION   = Select a new bitmap into the given ddc.
;*
;*                 Registers Preserved:
;*                       SI,DI,DS,BP
;*                 Registers Destroyed:
;*                       AX,BX,CX,DX,ES,FLAGS
;*                 
;* INPUT         = hdc     
;*                 Handle
;*                 pddc    
;*                 FunN    
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;*
;**************************************************************************/

ALIGN 4
DeviceSelectBitmap      PROC SYSCALL USES EBX edi esi,
        hdc     :DWORD,
        Handle  :DWORD,
        pddc    :DWORD,
        FunN    :DWORD

        DebugMsg <DeviceSelectBitmap DISPATCH SEL>
ifdef FIREWALLS
        ddc?    pddc,<MEMORYDDC,SURFACE>

;/*
;** If the bitmap handle passed in isn't NULL, then validate the
;** bitmap to make sure it isn't selected into another ddc.  It is
;** valid for it to be selected into this ddc.
;*/
        mov     esi,Handle              ;Null is allowed
        or      esi,esi
        jz      dsb_fw_ok_so_far

        ASSUME  esi:PTR BITMAP

        cmp     [esi].bm_sd.sd_usId,SURFACE_IDENT
        jne     dsb_bad_handle
        test    [esi].bm_sd.sd_fb,SD_DEVICE
        jnz     dsb_bad_handle
        cmp     [esi].bm_cSelect,0
        je      dsb_fw_ok_so_far
        mov     eax,pddc
        cmp     [esi].bm_hddc,eax
        je      dsb_fw_ok_so_far

dsb_bad_hddc_link:
;/*
;** Engine should have caught this
;*/
        rip     text,<DeviceSelectBitmap - Bitmap in use in different ddc>
        mov     eax,0
        jmp     dsb_tour_of_duty_over
ALIGN 4

dsb_bad_handle:
        rip     text,<DeviceSelectBitmap - Invalid bitmap or bitmap handle>
        mov     eax,0
        jmp     dsb_tour_of_duty_over
ALIGN 4

dsb_fw_ok_so_far:

;/*
;** The bitmap currently selected into the ddc must be linked back to
;** this pddc and have a lock count > 0.  If no bitmap is selected,
;** then ddc_npsd must be FFFF.  This was checked by the SURFACE command
;** to ddc?.  ddc? also checked to make sure there was a selector for
;** a non-null bitmap, or that it was zero for a NULL bitmap.
;*/

endif

        mov     esi,pddc                ;si --> ddc

        ASSUME  esi:PDDC

        mov     edx,esi
        INVOKE  enter_driver    
        jc      dsb_exit_no_lock        ; DX:AX = 0 on error


;/*
;** Unselect the bitmap currently selected into the DC.  The following
;** needs to be performed if there was a bitmap previously selected.
;**
;**In the ddc:
;**
;**       a) clear DDC_PRESENT to show no surface
;**
;**       b) clear DDC_NOTIFY_CLIP to show clipping is invalid
;**
;**       c) clear DDC_VISIBLE to show nothing shows
;**
;**       d) clear ddc_npsd to show no bitmap is selected
;**
;** In the bitmap:
;**
;**       e) decrement the selection count.
;**
;**       f) if the selection count is zero, clear bm_hddc to show
;**          a free bitmap.
;**
;*/

        INVOKE  deselect_bitmap     ;Deselect [SI].ddc_npsd


;/*
;** Select the new surface into the ddc.  If there isn't one, then steps
;** a through d from unselecting the surface will have performed all the
;** work necessary.  If there was no surface, then the state of these
;** flags would have been checked by the SURFACE portion of ddc? to make
;** sure that were correct.  If there is a new surface, then:
;**
;** In the bitmap:
;**
;**       a) increment the selection count.
;**
;**       b) Set bm_hddc to be this pddc.
;**
;** In the ddc:
;**
;**       d) Set ddc_npsd to the bitmap's handle
;**
;**       e) copy surface definition into the ddc.
;**
;**       c) Set DDC_PRESENT to show a surface
;**
;** Currently:
;**       SI --> pddc (ddc_)
;*/

dsb_old_unselected:

        ASSUME  edi:PTR BITMAP

        mov     edi,Handle              ;Only test .lo since we FIREWALLed
        or      edi,edi                 
        jz      dsb_new_selected        ;Null handle
        inc     [edi].bm_cSelect        ;Show another select
        mov     [edi].bm_hddc,esi       ;Show owned by this ddc
        mov     [esi].ddc_npsd,edi      ;--> new surface
        or      [esi].ddc_fb,DDC_PRESENT ;Show surface is present

dsb_new_selected:
        mov     eax,1

dsb_tour_of_duty_over:
        INVOKE  leave_driver
        ddc?    pddc,<SURFACE>          ;Make sure surface info is correct
dsb_exit_no_lock:
        fw_zero <ecx>
        ret
DeviceSelectBitmap ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = GetBitmapBits
;*
;* DESCRIPTION   = 
;*              This function transfers bitmap data from the specified bitmap to
;*              application storage. If hBitmap is NULL then the bitmap currently
;*              selected into the DC is used.  The DC must be a memory DC, with a
;*              bitmap currently selected.
;*             
;*              The format of the source bits is known only by the driver. The
;*              destination format must be one of the formats returned from
;*              QueryExternalBitmaps.  Conversion from device dependant format
;*              to standard format must occur as the bits are copied.  If the
;*              form is a non-standard format, then an error will be returned.
;*             
;*              The driver will translate the bitmap into the format requested
;*              by BitmapPlanes and BitmapBitcount if it is one of the external
;*              formats supported by the driver.
;*
;*              Registers Preserved:
;*                    SI,DI,DS,BP
;*              Registers Destroyed:
;*                    AX,BX,CX,DX,ES,FLAGS
;*                 
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = EAX = number of scans returned
;* RETURN-ERROR  = EAX = -1 if error
;*                 error logged
;*
;**************************************************************************/

ALIGN 4
GetBitmapBits   PROC SYSCALL USES EBX edi esi,
        hdc             :DWORD,
        hBitmap         :DWORD,
        ScanStart       :DWORD,
        ScanCount       :DWORD,
        lpAddress       :DWORD,
        lpInfo          :DWORD,
        pddc            :DWORD,
        FunN            :DWORD

        LOCAL  lpCompBits:DWORD              ;ptr to caller-supplied bits buffer
        LOCAL  lpCompInfo:DWORD              ;ptr to caller-supplied bitmap info
        LOCAL  fConvBM :BYTE                ;indicate there was a bitmap conversion

        NGBBF_CONV_BM   equ     00000001b   ;indicate a bitmap conversion

        DebugMsg <GetBitmapBits DISPATCH SEL>
        ddc?    pddc,<SURFACE>

        no_path_area    ngbb_log_error,both,error

;/*
;** Must have a memory ddc with a bitmap selected into it
;*/

        cmp     hBitmap,0               ;Did he give us a bitmap?
        je      ngbb_check_dc           ;No, go check the DC

                                        ;Yes, translate to a device handle
        INVOKE  GetDriverInfo,
                hBitmap,
                DI_HBITMAP,             ;MyIndex,
                hdc

;/*
;** Returns GPI_ALTERROR = 0ffffffffh if error
;*/
        mov     esi,eax                 ;ESI = source handle
        cmp     eax,GPI_ALTERROR
        jnz     ngbb_looks_good

        mov     eax,PMERR_INV_HBITMAP

ngbb_log_error:
        save_error_code
        mov     eax,-1
        jmp     ngbb_exit
ALIGN 4

ngbb_inv_option:
        mov     eax,PMERR_INV_OR_INCOMPAT_OPTIONS
        jmp     ngbb_log_error
ALIGN 4
ngbb_inv_info:
        mov     eax,PMERR_INV_INFO_TABLE
        jmp     ngbb_log_error
ALIGN 4

ngbb_insuff_mem_II:
        mov     ecx,lpInfo
        WAS_GLOBAL_FREE

ngbb_insuff_mem:
        mov     ax,PMERR_INSUFFICIENT_MEMORY
        jmp     ngbb_log_error
ALIGN 4

ngbb_check_dc:
        mov     esi,pddc

        ASSUME  esi:PDDC

        mov     cl,[esi].ddc_fb
        mov     eax,PMERR_INCORRECT_DC_TYPE
        test    cl,DDC_DEVICE
        jnz     ngbb_log_error
        mov     eax,PMERR_BITMAP_NOT_SELECTED
        test    cl,DDC_PRESENT
        jz      ngbb_log_error
        mov     esi,[esi].ddc_npsd

        ASSUME  esi:PTR BITMAP


; We have to allocate a temporary buffer if a compressed bitmap is requested.


ngbb_looks_good:
        mov     fConvBM,0               ;clear the bitmap conversion indicator
        mov     edi,lpInfo

        ASSUME  edi:PTR BITMAPINFOHEADER2

        .errnz  BITMAPINFOHEADER2.bmp2_cbFix
        .errnz  BITMAPINFOHEADER2.bmp2_cx-BITMAPINFOHEADER2.bmp2_cbFix-4
        .errnz  BITMAPINFOHEADER2.bmp2_cy-BITMAPINFOHEADER2.bmp2_cx-4
        .errnz  BITMAPINFOHEADER2.bmp2_cPlanes-BITMAPINFOHEADER2.bmp2_cy-4
        .errnz  BITMAPINFOHEADER2.bmp2_cBitCount-BITMAPINFOHEADER2.bmp2_cPlanes-2
        .errnz  BITMAPINFOHEADER2.bmp2_ulCompression-BITMAPINFOHEADER2.bmp2_cBitCount-2
        .errnz  BITMAPINFOHEADER2.bmp2_cbImage-BITMAPINFOHEADER2.bmp2_ulCompression-4
        .errnz  BITMAPINFOHEADER2.bmp2_cxResolution-BITMAPINFOHEADER2.bmp2_cbImage-4

        cmp     [edi].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_cxResolution
        jb      ngbb_extract_bits       ;compression not supported in old Info
        cmp     [edi].bmp2_ulCompression,BCA_UNCOMP
        je      ngbb_extract_bits       ;requested for a compressed bits ?
        cmp     [edi].bmp2_cBitCount,1
        jne     ngbb_alloc_buff
        mov     eax,ScanCount
        cmp     eax,[esi].bm_sd.sd_cy     ;if 1bpp, must be the entire bitmap.
        jb      ngbb_inv_option

;/*
;** We need to create a local bitmap info structure for uncompressed bits with
;** information from several source:-
;**       bmp2_cx         from    the bitmap width from its surface definition
;**       bmp2_cy         from    the number of scans requested
;**       bmp2_cPlanes    from    the caller-supplied bitmap info structure
;**       bmp2_cBitCount  from    the caller-supplied bitmap info structure
;** But first, we need to allocate a bitmap info structure. The reason why we
;** cannot allocate it on the stack because bmc_int_to_ext will allocate another
;** big chunk of memory for pallette which can sometimes cause stack overflow.
;*/

ngbb_alloc_buff:
        lea     ebx,lpInfo              ;EBX = where pointer goes
        movzx   ecx,[edi].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl                   ;AX = # of RGB entries
        shl     eax,2                    ;AX = size of color table
        .errnz  sizeof RGB2 - (1 shl 2)
        add     eax,BITMAPINFOHEADER2.bmp2_ulCompression
                                        ;EBX -> buffer to put allocated mem's
                                        ;       pointer into
                                        ;EAX = bitmap info's size
        mov     ecx,0                   ;ECX = buffer flag
        WAS_GLOBAL_ALLOC
        or      ecx,ecx                 ;if CX = 0, succeed
        jnz     ngbb_insuff_mem
        ; Allocated memory pointed to by lpInfo
        mov     ebx,lpInfo              ;EBX => decompressed bitmap info

        ASSUME  ebx:PTR BITMAPINFOHEADER2

        mov     [ebx].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_ulCompression ;copy upto color format
        mov     eax,[esi].bm_sd.sd_cx
        mov     [ebx].bmp2_cx,eax       ;the bitmap width
        mov     eax,ScanCount
        mov     [ebx].bmp2_cy,eax       ;the bitmap height
        mov     eax,dword ptr [edi].bmp2_cPlanes ;we only need the color format
        mov     dword ptr [ebx].bmp2_cPlanes,eax    ;(plane and bitcount)
        .ERRNZ  (sizeof BITMAPINFOHEADER2.bmp2_cBitCount) - 2
        .ERRNZ  (sizeof BITMAPINFOHEADER2.bmp2_cPlanes) - 2
        .ERRNZ  BITMAPINFOHEADER2.bmp2_cBitCount - BITMAPINFOHEADER2.bmp2_cPlanes - 2
        mov     lpCompInfo,edi          ;lpCompInfo points to
                                        ;the caller-supplied bitmap info

;/*
;** Allocate a storage for uncompressed bits
;**
;**     pass in:
;**      EBX->bitmapinfo struct
;**     returns:
;**      EAX->allocated buffer
;**      ECX=size in bytes
;**     error return:
;**      ECX=0
;*/
                                        ;we need EBX => local bitmap info
        INVOKE  alloc_uncomp_buffer     ;allocate a temporary buffer

        or      ecx,ecx
        jz      ngbb_insuff_mem_II      ;ECX = 0 if fails to allocate one

        mov     ecx,lpAddress           ;lpCompBits points to
        mov     lpCompBits,ecx          ;the caller-supplied buffer
        mov     lpAddress,eax           ;lpAddress points to
                                        ;the locally-allocated buffer
        or      fConvBM,NGBBF_CONV_BM   ;we will do conversion

;/*
;** Extract device-independent bitmap
;*/

ngbb_extract_bits:

        mov     edi,pddc

        ASSUME  edi:PDDC

        INVOKE  bmc_int_to_ext,
                esi,                    ; Bitmap
                lpInfo,                 ; -> Pointer to info block
                lpAddress,              ; -> Destination
                ScanCount,              ; Number of scans to copy
                ScanStart,              ; First scan to copy
                pddc                    ;          
;               [edi].ddc_pClrTbl       ; Used by some drivers, but not EGA


ngbb_compress_bits:

        test    fConvBM,NGBBF_CONV_BM   ;did we have a compression requested?
        jz      ngbb_exit         ;no, we are done!!
        mov     edi,lpCompInfo          ;EDI => caller-supplied bitmap info

        ASSUME  edi:PTR BITMAPINFOHEADER2

        mov     [edi].bmp2_cy,eax       ;AX = number of scans extracted

        mov     ebx,lpInfo              ;EBX => local bitmap info
        push    [ebx].bmp2_cy           ;we have to overwrite this for compression
        mov     [ebx].bmp2_cy,eax

        INVOKE  InnerGre32Entry9,
                hdc,
                CBD_COMPRESSION,
                0,
                lpInfo,
                lpAddress,
                lpCompInfo,
                lpCompBits,
                0,
                NGreConvertBitmapData

        push    eax                     ;save the return value from conversion
        mov     ecx,lpAddress           ;pointer in lpAddress
        INVOKE  private_free

        mov     ecx,lpInfo              ;pointer in lpInfo
        WAS_GLOBAL_FREE
        pop     eax

        mov     edi,lpCompInfo
        mov     edx,[edi].bmp2_cy       ;the return value from bmc_int_to_ext
        pop     [edi].bmp2_cy           ;we overwrote this for compression

;/*
;**  GreConvertBitmapData returns GPI_ERROR = 0 if failure
;*/
        .ERRNZ  GPI_ERROR
        dec     eax
        js      ngbb_exit               ;sign => compression failed
        mov     eax,edx                 ;value return from bmc_int_to_ext
                                        ; is eax=-1 on error
                                        ; or eax=#scans xlated if ok

ngbb_exit:
        fw_zero <ecx>
        ret
GetBitmapBits ENDP
page

;/***************************************************************************
;*
;* FUNCTION NAME = SetBitmapBits
;*
;* DESCRIPTION   = 
;*               This function transfers bitmap data from application storage to
;*               the specified bitmap. If hBitmap is NULL then the bitmap currently
;*               selected into the DC is used.  The DC must be a memory DC, with a
;*               bitmap currently selected.
;*               
;*               The format of the destination bits is known only by the driver.
;*               The source format must be one of the formats returned from
;*               QueryExternalBitmaps.  Conversion from standard format to
;*               device dependant format must occur as the bits are copied.
;*               
;*               Registers Preserved:
;*                     SI,DI,DS,BP
;*               Registers Destroyed:
;*                     AX,BX,CX,DX,ES,FLAGS
;*                 
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*    
;* RETURN-NORMAL = DX:AX = 1
;* RETURN-ERROR  = DX:AX = 0
;*                 error logged
;*
;**************************************************************************/

ALIGN 4
SetBitmapBits   PROC SYSCALL USES EBX edi esi,
        hdc             :DWORD,
        hBitmap         :DWORD,
        ScanStart       :DWORD,
        ScanCount       :DWORD,
        lpAddress       :DWORD,
        lpInfo          :DWORD,
        pddc            :DWORD,
        FunN            :DWORD

        LOCAL  lpLocalInfo:DWORD

        LOCAL  pbmiDecomp:PTR BITMAPINFOHEADER2    ;          

        LOCAL  fConvBM:BYTE                 ;indicate there was a bitmap conversion

        LOCAL colortablesize:DWORD          ;           Save color table size

        DebugMsg <SetBitmapBits DISPATCH SEL>

        NSBBF_CONV_BM   equ     00000001b   ;indicate a bitmap conversion
        ddc?    pddc,<SURFACE>

        no_path_area    nsbb_log_error,both,error

;/*
;** Must have a memory ddc with a bitmap selected into it
;*/

        cmp     hBitmap,0                ;Did he give us a bitmap?
        je      nsbb_check_dc            ;No, go check the DC

                                        ;Yes, translate to a device handle
        INVOKE  GetDriverInfo,
                hBitmap,
                DI_HBITMAP,             ;MyIndex,
                hdc

;/*
;** Returns GPI_ALTERROR = 0ffffffffh if error
;*/

        mov     esi,eax                 ;ESI = source handle
        cmp     eax,GPI_ALTERROR
        jnz     nsbb_looks_good
        mov     ax,PMERR_INV_HBITMAP
nsbb_log_error:
        save_error_code

nsbb_error_exit:
        mov     eax,-1
        jmp     nsbb_exit
ALIGN 4

nsbb_cbm_fail:
        mov     ecx,lpLocalInfo          ;selector of local bitmap info
        INVOKE  private_free
        mov     ecx,lpAddress            ;selector of decomp. bits in lpBits.sel
        INVOKE  private_free
        jmp     nsbb_error_exit
ALIGN 4

nsbb_insuff_mem_II:
        mov     ecx,lpLocalInfo
        WAS_GLOBAL_FREE

nsbb_insuff_mem:
        mov     eax,PMERR_INSUFFICIENT_MEMORY
        jmp     nsbb_log_error
ALIGN 4

nsbb_check_dc:
        mov     esi,pddc

        ASSUME  esi:PDDC

        mov     cl,[esi].ddc_fb
        mov     eax,PMERR_INCORRECT_DC_TYPE
        test    cl,DDC_DEVICE
        jnz     nsbb_log_error
        mov     eax,PMERR_BITMAP_NOT_SELECTED
        test    cl,DDC_PRESENT
        jz      nsbb_log_error

        mov     esi,[esi].ddc_npsd

        ASSUME  esi:PTR BITMAP


;/*
;** Now, we need to verify if the bits are in a compressed form. If so,
;** decompress them before setting them.
;*/

nsbb_looks_good:

        mov     fConvBM,0               ;clear the bitmap conversion indicator
        mov     edi,lpInfo


        ASSUME  edi:PTR BITMAPINFOHEADER2

        .errnz  BITMAPINFOHEADER2.bmp2_cbFix
        .errnz  BITMAPINFOHEADER2.bmp2_cx-BITMAPINFOHEADER2.bmp2_cbFix-4
        .errnz  BITMAPINFOHEADER2.bmp2_cy-BITMAPINFOHEADER2.bmp2_cx-4
        .errnz  BITMAPINFOHEADER2.bmp2_cPlanes-BITMAPINFOHEADER2.bmp2_cy-4
        .errnz  BITMAPINFOHEADER2.bmp2_cBitCount-BITMAPINFOHEADER2.bmp2_cPlanes-2
        .errnz  BITMAPINFOHEADER2.bmp2_ulCompression-BITMAPINFOHEADER2.bmp2_cBitCount-2
        .errnz  BITMAPINFOHEADER2.bmp2_cbImage-BITMAPINFOHEADER2.bmp2_ulCompression-4
        .errnz  BITMAPINFOHEADER2.bmp2_cxResolution-BITMAPINFOHEADER2.bmp2_cbImage-4

        cmp     [edi].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_cxResolution
        jb      nsbb_set_bits           ;compression not supported in old Info
        cmp     [edi].bmp2_ulCompression,BCA_UNCOMP
        je      nsbb_set_bits           ;not a compressed bits

;/*
;** We will have to modify the content of the source bitmap info structure,
;** hence create its local copy and use it in place of the source structure.
;*/

nsbb_decompress_bits:

        lea     ebx,pbmiDecomp          ;EBX = where selector goes ;                      
        mov     eax,BITMAPINFOHEADER2.bmp2_ulCompression + (256*size RGB2)
                                        ;EAX = Size
        mov     ecx,0                   ;ECX = buffer flag
        INVOKE  private_alloc
        or      ecx,ecx                 ;if ECX = 0, succeed
        jnz     nsbb_insuff_mem

        or      fConvBM,NSBBF_CONV_BM   ;we will do conversion
        lea     ebx,lpLocalInfo         ;EBX = where selector goes
        movzx   ecx,[edi].bmp2_cBitCount
        mov     eax,1
        shl     eax,cl                   ;AX = # of RGB entries

        mov     colortablesize,eax       ;           Save color table size

        shl     eax,2                    ;AX = size of color table
        .errnz  sizeof RGB2 - (1 shl 2)
        add     eax,[edi].bmp2_cbFix
                                        ;EAX = bitmap info's size
        mov     edi,eax                 ;save the size for future
        mov     ecx,0                   ;CX = buffer flag
        WAS_GLOBAL_ALLOC
        or      ecx,ecx                 ;if ECX = 0, succeed
        jnz     nsbb_insuff_mem
        xchg    ecx,edi                 ;EDI = size of bmi and ECX = 0

;/*
;** edi = 0
;** ecx = sizeof bmi
;**  lpLocalInfo->buffer allocated
;*/
        push    esi                     ;save near ptr to surface definition
        mov     esi,lpInfo
        mov     edi,lpLocalInfo

        ASSUME  edi:PTR BITMAPINFOHEADER2
        ASSUME  esi:PTR BITMAPINFOHEADER2

        mov     eax,ecx
        shr     ecx,2
        rep     movsd
        mov     ecx,eax
        and     ecx,3
        rep     movsb
        sub     esi,eax                   ;ESI => source bitmap info structure

;/*
;** We want to duplicate the bitmapinfo structure from bmp2_cx to bmp2_cBitCount
;** fields, allocate a buffer for uncompressed bits, and may have to initialize
;** it with the contents of the destination bitmap.
;*/

        mov     ebx,pbmiDecomp            ;           
        mov     edi,ebx

        ASSUME  ebx:PTR BITMAPINFOHEADER2

        mov     ecx,BITMAPINFOHEADER2.bmp2_ulCompression
        shr     ecx,2

        .errnz  BITMAPINFOHEADER2.bmp2_ulCompression and 3

        rep     movsd                   ;we need information

        mov     [ebx].bmp2_cbFix,BITMAPINFOHEADER2.bmp2_ulCompression   ;upto bmp2_cBitCount
        mov     eax,ScanCount
        mov     [ebx].bmp2_cy,eax       ;and requested height
        pop     esi                     ;ESI => surface definition

        INVOKE  alloc_uncomp_buffer     ;allocate a temporary buffer
        or      ecx,ecx
        jz      nsbb_insuff_mem_II      ;ECX = 0 if fails to allocate one

        xchg    lpAddress,eax

        mov     edi,lpLocalInfo
        mov     ecx,[edi].bmp2_cy       ;ECX = full height of bitmap
        xchg    ecx,ScanCount           ;ScanCount now stores the full height
        mov     [edi].bmp2_cy,ecx       ;the actual height of bitmap to decomp
        cmp     [edi].bmp2_ulCompression,BCA_HUFFMAN1D
        je      nsbb_init_done

        mov     edi,pddc

        ASSUME  edi:PDDC

        mov     ebx,pbmiDecomp          ;           
        push    ecx                     ;save # of scans requested

        push    eax                     ;save ptr to compressed bits
        INVOKE  bmc_int_to_ext,
                esi,                    ; Bitmap
                ebx,                    ; -> Pointer to info block
                lpAddress,              ; -> buffer of source bits
                ecx,                    ; Number of scans to copy
                ScanStart,              ; First scan to copy
                pddc                    ;          
;               [edi].ddc_pClrTbl       ; Used by some drivers, but not EGA

        pop     eax

;           Copy color table from source bitmap to destination bitmap
        push    edi                     ;          
        push    esi                     ;          
        mov     esi,lpInfo              ;           Point to src bmi
        add     esi,[esi].bmp2_cbFix    ;           Add offset to color table
        mov     edi,ebx                 ;           Point to dest bmi
        add     edi,BITMAPINFOHEADER2.bmp2_ulCompression ;           Add offset to color table
        mov     ecx,colortablesize      ;           Move size of color table
        .errnz  sizeof RGB2 - 4         ;          
        rep     movsd                   ;          
        pop     esi                     ;          
        pop     edi                     ;          

        mov     ebx,pbmiDecomp          ;           
        pop     [ebx].bmp2_cy           ;restore the number of scans requested

nsbb_init_done:
        mov     edx,eax

        INVOKE  InnerGre32Entry9,
                hdc,                  ;hdc
                CBD_DECOMPRESSION,    ;ulCmd
                CBD_COLOR_CONVERSION, ;ulOption
                lpLocalInfo,          ;pbmiSrc
                edx,                  ;pbBitsSrc
                ebx,                  ;pbmiDst
                lpAddress,            ;pbBitsDst
                0,                    ;pddc
                NGreConvertBitmapData ;ulFunN

        or      eax,eax
        jz      nsbb_cbm_fail           ;if failed, we can get out of here now

        mov     ebx,pbmiDecomp          ;           
        mov     ecx,ScanCount
        xchg    [ebx].bmp2_cy,ecx       ;full height in this bitmap info
        mov     ScanCount,ecx           ;# of scan requested in ScanCount
        mov     lpInfo,ebx              ;then use it to set uncompressed
                                        ;bitmap

;/*
;** At this point, the bits should be in the decompressed form.
;*/

nsbb_set_bits:

        INVOKE  bmc_ext_to_int,
                esi,                    ; Bitmap
                lpInfo,                 ; -> Pointer to info block
                lpAddress,              ; -> buffer of source bits
                ScanCount,              ; Number of scans to copy
                ScanStart,              ; First scan to copy
                pddc                     ; pddc

;/*
;** Returns:
;**       EAX = # of scanlines translated
;** Error Returns:
;**       EAX = -1
;*/


;/*
;** Now we can free the temporary decompressed buffer, if any.
;*/    
        test    fConvBM,NSBBF_CONV_BM       ;did we do conversion?
        jz      nsbb_exit
        push    eax
        mov     ecx,lpLocalInfo             ;selector of local bitmap info
        INVOKE   private_free
        mov     ecx,lpAddress               ;selector in lpAddress.sel
        INVOKE   private_free

        mov     ecx,pbmiDecomp               ;selector in lpAddress.sel
        INVOKE   private_free                ;           

        pop     eax

nsbb_exit:
        fw_zero <ecx>
        ret
SetBitmapBits ENDP


page
;/***************************************************************************
;*
;* FUNCTION NAME = check_bitmap_info
;*
;* DESCRIPTION   = 
;*           This function validates various fields of the passed BITMAPINFOHEADER
;*           structure, and returns an index based on the format passed.
;*
;*           Registers Preserved:
;*                 BX,DX,DI,DS,ES,BP
;*           Registers Destroyed:
;*                 FLAGS,AX,CX,GS,SI
;* INPUT         
;*      ES:BX --> BITMAPINFOHEADER or BITMAPINFOHEADER2 structure
;*      CX <> 0 --> Check all entered fields
;*      CX == 0 --> Check only those fields required by GetBitmapBits
;*
;* OUTPUT        = NONE
;*    
;* RETURN-NORMAL = CX  <> 0 if format recognized
;*                 AX = 0 if format is 1 plane,  1 bit-per-pixel
;*                 AX = 4 if format is 1 plane,  4 bit-per-pixel
;*                 AX = 8 if format is 1 plane,  8 bit-per-pixel
;*                 AX = 12 if format is 1 plane, 24 bit-per-pixel
;*
;* RETURN-ERROR  = CX   = 0 if format isn't one of the above
;*
;**************************************************************************/

ALIGN 4
check_bitmap_info   PROC SYSCALL USES ESI

        ASSUME  ebx:PTR BITMAPINFO2

        mov     esi,[ebx].bmi2_cbFix
        cmp     esi,SIZE BITMAPINFOHEADER
        jne     cbmi_new_header

        ASSUME  ebx:PTR BITMAPINFO

        movzx   ecx,[ebx].bmi_cBitCount
        movzx   eax,[ebx].bmi_cPlanes
        jmp     cbmi_check_bitcount_and_planes
ALIGN 4
cbmi_new_header:
        cmp     esi,SIZE BITMAPINFOHEADER2
        ja      cbmi_invalid_format
        je      cbmi_ulIdentifier

        shr     esi,1
        jc      cbmi_invalid_format
        add     esi,OFFSET ok_cbFix

        ASSUME  esi:NOTHING

        movzx   esi,BYTE PTR [esi]

        add     esi,OFFSET bmi2_check_point
        movzx   esi,BYTE PTR [esi]
        add     esi,OFFSET cbmi_ulIdentifier
        jmp     esi
ALIGN 4
cbmi_ulIdentifier::
cbmi_ulColorEncoding::

        ASSUME  ebx:PTR BITMAPINFO2


        cmp     [ebx].bmi2_ulColorEncoding,BCE_RGB
        je      cbmi_cSize1
        cmp     [ebx].bmi2_ulColorEncoding,BCE_PALETTE
        jne     cbmi_invalid_format
cbmi_cSize1::
cbmi_cSize2::
cbmi_usRendering::
        cmp     [ebx].bmi2_usRendering,BRH_NOTHALFTONED
        jne     cbmi_invalid_format
cbmi_usRecording::
        cmp     [ebx].bmi2_usRecording,BRA_BOTTOMUP
        jne     cbmi_invalid_format
cbmi_usReserved::
        cmp     [ebx].bmi2_usReserved,0
        jne     cbmi_invalid_format
cbmi_usUnits::
        jecxz   cbmi_cBitCount      ; CX must be preserved until here
        cmp     [ebx].bmi2_usUnits,BRU_METRIC
        jne     cbmi_invalid_format
cbmi_cclrImportant::
        jecxz   cbmi_cBitCount
        movzx   ecx,[ebx].bmi2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
        cmp     [ebx].bmi2_cclrImportant,eax
        ja      cbmi_invalid_format
        jmp     cbmi_computed_max_colors_already
ALIGN 4
cbmi_cclrUsed::
        jecxz   cbmi_cBitCount
        movzx   ecx,[ebx].bmi2_cBitCount
        mov     eax,1
        shl     eax,cl              ;CL is taken mod 32 by the instruction
cbmi_computed_max_colors_already::
        cmp     [ebx].bmi2_cclrUsed,eax
        ja      cbmi_invalid_format
cbmi_cyResolution::
cbmi_cxResolution::
cbmi_cbImage::
        cmp     [ebx].bmi2_ulCompression,BCA_UNCOMP
        je      cbmi_cBitCount
        .errnz  BCA_UNCOMP
        .errnz  BCA_RLE8-1
        .errnz  BCA_RLE4-2
        .errnz  BCA_HUFFMAN1D-3
        .errnz  BCA_RLE24-4
        cmp     [ebx].bmi2_ulCompression,BCA_RLE24
        ja      cbmi_invalid_format
        cmp     [ebx].bmi2_cbImage,0      ;must be non-zero for compressed
        jne     cbmi_cBitCount        ;bitmap
        jmp     cbmi_invalid_format
ALIGN 4
cbmi_ulCompression::
        cmp     [ebx].bmi2_ulCompression,BCA_UNCOMP
        jne     cbmi_invalid_format
cbmi_cBitCount::
        movzx   ecx,[ebx].bmi2_cBitCount
        movzx   eax,[ebx].bmi2_cPlanes

cbmi_check_bitcount_and_planes::
        cmp     eax,1
        jne     cbmi_invalid_format
        mov     eax,0                   ;Index = 0
        cmp     ecx,1
        je      cbmi_have_format
        inc     eax                     ;Index = 1
        cmp     ecx,4
        je      cbmi_have_format
        inc     eax                     ;Index = 2
        cmp     ecx,8
        je      cbmi_have_format
        inc     eax                     ;Index = 3
        cmp     ecx,24
        je      cbmi_have_format
cbmi_invalid_format::
        mov     ecx,0
cbmi_have_format:
        shl     eax,2                   ;*4 for correct values
cbmi_exit:
        ret
check_bitmap_info ENDP
page

;/***************************************************************************
;*
;* FUNCTION NAME = deselect_bitmap
;*
;* DESCRIPTION   =
;*            This function deselects a bitmap from a ddc if one is selected in.
;*            This is used by both RestoreDC and SelectBitmap.
;*
;*            Registers Preserved:
;*                  AX,CX,DX,SI,DI,DS,ES,BP
;*            Registers Destroyed:
;*                  BX,FLAGS
;*
;* INPUT         = DS:SI --> memory ddc
;*
;* OUTPUT        = NONE
;*    
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
;
;/*
;**    ---------------------Pseudo-Code------------------------------
;** {
;**
;** // In the ddc:
;** //
;** //    a) clear DDC_PRESENT to show no surface
;** //
;** //    b) clear DDC_CLIP_NOTIFY to show clipping is invalid
;** //
;** //    c) clear DDC_VISIBLE to show nothing shows
;** //
;** //    d) clear ddc_npsd to show no bitmap is selected
;** //
;** // In the bitmap:
;** //
;** //    e) decrement the selection count.
;** //
;** //    f) if the selection count is zero, clear bm_hddc to show
;** //       a free bitmap.
;**
;** }
;*/

ALIGN 4
deselect_bitmap     PROC SYSCALL
        DebugMsg <deselect_bitmap SEL>

        ddc?    esi,<SURFACE,MEMORYDDC>

        ASSUME  esi:PDDC

        mov     ebx,INVALID_ADDRESS
        xchg    ebx,[esi].ddc_npsd
        inc     ebx
        jz      dbm_done                ;No bitmap to deselect
        .errnz  INVALID_ADDRESS+1
        dec     ebx

        ASSUME  ebx:PTR BITMAP

        dec     [ebx].bm_cSelect
        jnz     dbm_still_owned
        mov     [ebx].bm_hddc,INVALID_ADDRESS ;No longer owned
dbm_still_owned:
        and     [esi].ddc_fb,not (DDC_PRESENT or DDC_CLIP_NOTIFY or DDC_VISIBLE)
dbm_done:
        ret
deselect_bitmap ENDP

page

;/***************************************************************************
;*
;* FUNCTION NAME = save_bitmap
;*
;* DESCRIPTION   =
;*            This function is called from SaveDC to perform whatever operations
;*            are necessary to save the bitmap portion of the ddc.
;*           
;*            The caller has already checked to see if a bitmap is selected into
;*            the ddc.
;*           
;*            Registers Preserved:
;*                  AX,CX,DX,SI,DI,DS,ES,BP
;*            Registers Destroyed:
;*                  BX,FLAGS
;*
;* INPUT         = DS:SI --> ddc_
;*
;* OUTPUT        = NONE
;*    
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

ALIGN 4
save_bitmap     PROC SYSCALL
        DebugMsg <save_bitmap    SEL>

        ASSUME  esi:PDDC
        ASSUME  ebx:PTR BITMAP

ifdef FIREWALLS
        ddc?    esi,<MEMORYDDC>
        mov     ebx,[esi].ddc_npsd
        cmp     [ebx].bm_sd.sd_usId,SURFACE_IDENT
        jne     save_bm_bad_surface
        test    [ebx].bm_sd.sd_fb,SD_DEVICE
        jz      save_bm_good_surface
save_bm_bad_surface:
        rip     text,<save_bitmap - Surface is not a bitmap>
save_bm_good_surface:
endif

        inc     [ebx].bm_cSelect
        ret
save_bitmap ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = alloc_uncomp_buffer
;*
;* DESCRIPTION   =
;*            This function is called from DeviceCreateBitmap and SetBitmapBits to
;*            allocate a buffer to store bits the dimension of which is specified in
;*            a bitmapInfo structure. The function assumes this bits one of the
;*            standard format.
;*            
;*            Registers Preserved:
;*                  DS,ES,SI,DI,BP
;*            Registers Destroyed:
;*                  AX,BX,ECX,DX,FLAGS
;*            
;* INPUT         = EBX   --> bitmapInfo structure   
;*
;* OUTPUT        = NONE
;*    
;* RETURN-NORMAL = EAX   --> allocated buffer
;*                 ECX       its size (in bytes)
;* RETURN-ERROR  = ECX = 0
;*
;**************************************************************************/

ALIGN 4
alloc_uncomp_buffer     PROC SYSCALL
        LOCAL  lpBuffer:DWORD
        LOCAL  lSize:DWORD

;/*
;** calculate the bits size from the bitmap dimension
;*/


        ASSUME  ebx:PTR BITMAPINFOHEADER2

        mov     eax,[ebx].bmp2_cx           ;number of pels per scan

                                            ;mul: EDX:EAX <- EAX * SRC
                                            ;cBitCount is # bits per pel
                                            ; within a plane
        mul     [ebx].bmp2_cBitCount        ;EDX:EAX = number of bits per
                                            ; scan
        add     eax,31
        adc     edx,0
        shrd    eax,edx,5                   ;number of dwords per scan
        shl     eax,2                       ;number of bytes per scan

        mul     [ebx].bmp2_cy               ;EAX = bits size = scansize * height
        mov     lSize,eax
        lea     ebx,lpBuffer                ;EBX = where the selector returned
        INVOKE  private_alloc
        jecxz   aub_return                  ;ECX = 0 if successful
        mov     eax,0
        mov     lSize,eax                   ;we will return size 0 as failure

aub_return:
        mov     ecx,lSize                   ;return size
        mov     eax,lpBuffer                ;return pointer
        ret
alloc_uncomp_buffer ENDP
end
