;*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.;
;*****************************************************************************/
ifdef DCAF
        PAGE    ,132
        TITLE   EXPAND.ASM
;/*****************************************************************************
;*
;* SOURCE FILE NAME = EXPAND.ASM
;*
;* DESCRIPTIVE NAME = DCAF expansion code used by SetScreenBits.
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/22/92
;*
;* DESCRIPTION
;*
;* FUNCTIONS
;*              Planar4bppRectangle
;*              Packed4bppRectangle
;*              InvalidFormat
;*              DecompressScreenBits
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/22/92                     Created for DCAF 1.3
;*   07/01/92                     Ported to 32-bit for DCAF 2.0
;*
;*****************************************************************************/

        .xlist
        .386p

INCL_DDICOMFLAGS        equ     1
INCL_GRE_REGIONS        equ     1
INCL_GPIREGIONS         equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1
        include pmgre.inc
        include driver.inc
        include assert.mac
        include protos.inc
        include extern.inc

INCL_GPIERRORS          equ     1
        include pmerr.inc

        include dcafmac.inc
        .list

        .MODEL  FLAT
        ASSUME  CS:FLAT, SS:FLAT, DS:FLAT, ES:FLAT

;/*
;** These defines make the comparisons easier later on
;*/
planar    equ 1
packed_4  equ 4
packed_8  equ 8
packed_16 equ 16


;/*
;** We have a number of versions of ProcessOneRectangle for each of
;** the formats a driver supports.  They are all generated from a
;** single set of source.
;** All the labels are defined as locals since the macro is used more than
;** once.
;*/
ProcessOneRectangle_body macro format
        local   next_scan
        local   next_scan_relay
        local   within_a_scan
        local   next_cell
        local   not_next_scan
        local   not_mid_zero
        local   non_rle
        local   repeat_type
        local   on_first_plane
        local   last_exists
        local   count_in_eax
        local   enough_scans_left
        local   each_repeat
        local   pop_then_next_scan
        local   dual_repeat
        local   lastbut1_exists
        local   panic_exit
        local   done_all_scans
        local   final_exit
        local   next_seg
        local   small_bitmap
        local   segment_change
        local   src_segment_change
        local   no_src_change
        local   dest_segment_change
        local   seg_change


;/*
;** Set up so that @FLD8 and @FLD16 macros work dependant on the unit
;** size of the format this routine is working on.
;*/
if (format eq planar) or (format eq packed_4)
        INITFIELDSIZE    8
endif ; (format eq planar) or (format eq packed_4)
if (format eq packed_8) or (format eq packed_16)
        INITFIELDSIZE    16
endif ; (format eq packed_8) or (format eq packed_16)

;/*
;** Some clarification of terminology may be in order here.
;**
;** A unit/field  - a byte for 4bpp formats, a word for all others
;** A cell        - a number of units representing a run of pels
;** (either an RLE run, a non compressed run, or a
;** repeat scanline run)
;** A scanline    - all the data for a line of screen/bitmap data
;** A scan        - a scanline if packed, or a plane if planar
;**
;** A full width scan or scanline, is the width of the bitmap.
;** If unqualified, a scan or scanline is the width of the rectangle.
;*/

;/*
;** We need our string instructions to increment
;*/
        cld

ifdef FIREWALLS
;/*
;** Set the previous pointers to NULL.
;** This allows us to double check the data we are passed - if
;** these are still null when we come to use tham then we have
;** been given a repeat line code in the       place.
;*/
        xor     eax,eax
        mov     pLastScanline, eax
        mov     pLastBut1Scanline, eax
endif ; FIREWALLS

;/*
;** Move some important values from the bitmap header into local
;** scope.
;** This is driver specific.
;*/
        mov     esi,pBitmap             ; Get the VGA surface definition
        ASSUME  ESI:PTR SURFACE
        mov     eax,[esi].sd_cbScan     ; Get index to next plane
        mov     cbScanDelta, eax

;/*
;** Process the rectangle, to determine how much work there is to do.
;*/
        mov     ebx, prcl
        ASSUME  EBX:PTR RECTL
        mov     eax, [ebx].rcl_xRight
        sub     eax, [ebx].rcl_xLeft

if (format eq planar)
;/*
;** Planar format (ie 4bpp) has 8 pels per unit (of a byte) on each scan
;*/
        shr     eax, 3                  ; divide by 8 (since 8 pels per byte)
endif ; (format eq planar)
if (format eq packed_4)
;/*
;** We need to store the number of pels for the unpacking call
;*/
        mov     cPels,eax
;/*
;** 4bpp packed format has 2 pels per unit (of a byte)
;*/
        shr     eax, 1                  ; divide by 2 (since 2 pels per byte)
endif ; (format eq packed_4)
        mov     cUnitsPerScan, eax

if (format eq packed_4)
;/*
;** The cbEndOfScanInc applies within a plane when on packed_4 data
;** so divide again by 4 (making 8 in total)
;** since within planar data there are 8 pels per byte.
;*/
        shr     eax, 2                  ; divide by 4 (since 8 pels per byte)
endif ; (format eq packed_4)

;/*
;** Having saved the number of units per scan, we now need to
;** change this number back to bytes for the next calculation
;*/
@FLD16 <add     eax,eax>

;/*
;** Find the increase from the end of one scan to the start of the next.
;*/
        mov     edx,cbScanDelta         ; bytes per full width scan
        sub     edx,eax                 ; subtract the amount processed
        mov     cbEndOfScanInc, edx

;/*
;** Find the number of scans to process
;*/
        mov     eax, [ebx].rcl_yTop
        sub     eax, [ebx].rcl_yBottom
if (format eq planar)
;/*
;** Planar format has 4 scans for each scanline in the passed rectangle
;*/
        shl     eax,2                   ; mult by 4 to go from lines to planes
endif ; (format eq planar)
        mov     cScansToDo, eax

;/*
;** Find the address of the start of the rectangle we are going to
;** write to.
;** The data is provided from the top of the rectangle down.
;** This is very driver specific.
;** (VGA version is based on code from pixel.asm)
;*/
        mov     eax,[esi].sd_cy
        sub     eax,[ebx].rcl_yTop      ; Have now flipped y coord

        mov     edi,[esi].sd_pBits      ; Load pointer to the bitmap bits
        mov     ebx,[esi].sd_dScan      ; Get bytes per scan
        mul     ebx                     ; Compute offset of start of scan
        add     edi,eax                 ; Add to start of bitmap

;/*
;** EDI -> start of the correct scan in the bitmap
;*/
        mov     ebx, prcl               ; Get the pointer to the rectl
        mov     eax,[ebx].rcl_xLeft     ; Get X coordinate
        shr     eax,3                   ; Compute byte offset from start of scan
        add     edi,eax                 ; cx:di --> byte of pixel

;/*
;** EDI -> the byte holding the corner of the rectangle
;*/

;/*
;** Get the data buffer pointer
;*/
        mov     esi, pBuffer

;/*
;** This is the top of the each scan loop
;**
;** 32 bit EDI -> the leftmost unit of current scan
;** 32 bit ESI -> the current unit of compressed data
;*/
next_scan:
        cmp     cScansToDo, 0
        jz      done_all_scans

        mov     eax, cUnitsPerScan
        mov     cUnitsToDo, eax

;/*
;** Get the next unit to expand from the buffer.
;*/
        xor     eax,eax         ; zero the top half so we can use whatever
                                ; size of register we want and still get the
                                ; same value.

@FLD8  <lodsb>
@FLD8  <and     al,al>
@FLD16 <lodsw>
@FLD16 <and     ax,ax>

if (format eq packed_4)
        jz       repeat_type    ; zero unit means a repeat scanline unit
else
        jz      repeat_type     ; zero unit means a repeat scanline unit
endif ; (format eq packed_4)

;/*
;** We must keep our previous scanline pointers up to date.
;** NB. we use edx, to avoid changing the value in eax
;*/
if (format eq planar)
;/*
;** We should only do this on the first plane
;*/
        test    cScansToDo, 3
        jnz     within_a_scan
endif ; (format eq planar)

        mov     edx,pLastScanline
        mov     pLastBut1Scanline,edx
        mov     pLastScanline,edi

if (format eq packed_4)
;/*
;** If we are handling packed (4bpp) data on the VGA then we
;** must expand the data into a buffer, then later unpack the
;** buffer into the planar format
;*/
        mov     pPlanar,edi     ; save the planar format destination
        lea     edi, pelbuffer
endif ; (format eq packed_4)

within_a_scan:
@FLD8  <and     al,al>
@FLD16 <and     ax,ax>
        js      non_rle

;/*
;** We have an RLE encoded run
;*/
        mov     ecx,eax                 ; this is the repeat count
        assert  ecx,LE,cUnitsToDo
        sub     cUnitsToDo, ecx
@FLD8  <lodsb>                          ; this is the byte to repeat
@FLD8  <rep     stosb>                  ; expand the run length
@FLD16 <lodsw>                          ; this is the byte to repeat
@FLD16 <rep     stosw>                  ; expand the run length

next_cell:
;/*
;** We move to the next cell.
;**
;** If we have completed a scan then we move to the next scan.
;** The last instruction to affect the flags before arriving at this
;** instruction was a 'sub cUnitsToDo, ax'
;** Thus the zero flag will be set if we have reached the end of
;** a scan, and can move to the next scan.
;*/

;;      cmp     cUnitsToDo, 0  ; unnecessary !
        jnz     not_next_scan
        dec     cScansToDo

if (format eq packed_4)
;/*
;** If we are handling packed (4bpp) data on the VGA then we
;** have just expanded the data into a buffer.
;** We must now unpack the buffer into the planar memory bitmap.
;**
;** Currently we have
;** edi -> the last byte we wrote in our temporary buffer
;** This is of no further use to us !
;** We reset edi to the start of the buffer which is far more useful.
;*/

;/*
;** We can't call UnPackBuffer directly...
;**     INVOKE  UnPackBuffer, pPlanar, ADDR pelbuffer, cPels, cbScanDelta
;*/

;/*
;** We now call the UnPackBuffer routine indirectly because its
;** address is loaded at run-time.
;*/
        INVOKE  PFNUnPackBuffer PTR pfnUnPackBuffer,
                              pPlanar, ADDR pelbuffer, cPels, cbScanDelta

        mov     edi, pPlanar            ; the saved start of this scanline
;/*
;** Move to the next scanline.
;*/
        mov     eax,cbScanDelta
        shl     eax,2                   ; mult by 4 since 4 planes
        add     edi,eax                 ; move to the next scanline
endif ; (format eq packed_4)

if (format eq planar)
;/*
;** Now we need to move to the next scan line.
;*/
        add     edi,cbEndOfScanInc
endif ; (format eq planar)

        jmp     next_scan

not_next_scan:
        xor     eax,eax         ; zero the top half so we can use whatever
                                ; size of register we want and still get the
                                ; same value.
@FLD8  <lodsb>
@FLD8  <and     al,al>                  ; set the flags
@FLD16 <lodsw>
@FLD16 <and     ax,ax>                  ; set the flags
ifdef FIREWALLS
        jnz     not_mid_zero
        rip     text,<Repeat encountered in mid scan>
        jmp     panic_exit
not_mid_zero:
endif ; FIREWALLS
        jmp     within_a_scan

non_rle:
        mov     ecx,eax
@FLD8  <and     ecx, 7fh>               ; clear the top bit to get the count
@FLD16 <and     ecx, 7fffh>             ; clear the top bit to get the count
        assert  ecx,LE,cUnitsToDo
        sub     cUnitsToDo, ecx
@FLD8  <rep     movsb>
@FLD16 <rep     movsw>
        jmp     next_cell

repeat_type:
;/*
;** We have some form of scanline repeat code.
;*/

if (format eq planar)
ifdef FIREWALLS
;/*
;** A repeat field should only come at the start of the first plane
;*/
        test    cScansToDo, 3
        jz      on_first_plane
        rip     text,<Repeat encountered not on first plane>
        jmp     panic_exit
on_first_plane:
endif ; FIREWALLS
endif ; (format eq planar)

@FLD8  <lodsb>                          ; next byte determines type of repeat
@FLD8  <and     al,al>
@FLD16 <lodsw>                          ; next word determines type of repeat
@FLD16 <and     ax,ax>
        jz      dual_repeat

ifdef FIREWALLS
        cmp     pLastScanline, 0
        jne     last_exists
        rip     text,<Repeat last encountered on first scan>
        jmp     panic_exit
last_exists:
endif ; FIREWALLS

;/*
;** We have a 'repeat last scanline' code
;*/
        push    esi     ; Save the buffer pointer

        mov     esi,pLastScanline

count_in_eax:
;/*
;** eax holds the number of times to repeat
;*/
        mov     ebx, eax                ; move the count to a safe register

if (format eq planar)
        shl     eax,2                   ; * 4 because cScansToDo counts planes
endif ; (format eq planar)

ifdef FIREWALLS
        cmp     cScansToDo, eax
        jae     enough_scans_left
        rip     text,<Repeat gives too many scans>
        pop     esi                     ; clean the stack etc
        jmp     panic_exit
enough_scans_left:
endif ; FIREWALLS
        sub     cScansToDo, eax

;/*
;** This is VGA, we need to copy 4 planes of data for each scanline
;*/
        mov     ecx,cUnitsPerScan
if (format eq packed_4)
        ; cUnitsPerScan was pels / 2 (packed 4bpp) but now we want
        ; the number of bytes per scan which has 8 pels per byte
        shr     ecx,2                   ; pels / 2 / 4 = pels / 8
endif ; (format eq packed_4)
        mov     edx,ecx                 ; keep this in a register for reuse
        mov     eax,cbEndOfScanInc        ; get the increment between scans

each_repeat:
;/*
;** Update the previous scans pointers
;*/
        mov     pLastBut1Scanline,esi
        mov     pLastScanline,edi

;/*
;** VGA requires 4 planes of data to be repeated
;*/

;/*
;** Copy the first plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
;/*
;** Copy the second plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
;/*
;** Copy the third plane
;*/
        rep     movsb

        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        mov     ecx,edx
;/*
;** Copy the fourth plane
;*/
        rep     movsb

;/*
;** Exit the loop if we have done all the repeats
;*/
        dec     ebx
        jz      pop_then_next_scan

;/*
;** Reload ecx for the next pass through the loop
;*/
        mov     ecx,edx

;/*
;** Move to the next scanline
;*/
        add     esi,eax                 ; move to start of next plane
        add     edi,eax                 ; move to start of next plane
        jmp     each_repeat

pop_then_next_scan:
        pop     esi

        add     edi,cbEndOfScanInc
        jmp     next_scan

dual_repeat:
;/*
;** We have a 'repeat last 2 scanlines' code
;*/
@FLD8  <lodsb>                          ; find how many times to repeat
@FLD16 <lodsw>                          ; find how many times to repeat
        add     eax,eax                 ; dual requires twice as many lines

ifdef FIREWALLS
        cmp     pLastScanline, 0
        jne     lastbut1_exists
        rip     text,<Repeat last 2 encountered before third scan>
lastbut1_exists:
endif ; FIREWALLS

        push    esi     ; Save buffer pointer

        mov     esi,pLastBut1Scanline
        jmp     count_in_eax

panic_exit:
        mov     ax,PMERR_INV_IMAGE_FORMAT
        save_error_code

        xor     eax,eax
        jmp     final_exit

done_all_scans:
        mov     eax,esi

final_exit:

ENDM



        .DATA

        PUBLIC  pelbuffer
pelbuffer  BYTE    1024 DUP (?)


        .CODE


;--------------------------Internal-Routine-----------------------------;
;/*********************************************************************
;* ProcessOneRectangle                                                *
;*   (Planar4bppRectangle)                                            *
;*   (Packed4bppRectangle)                                            *
;*                                                                    *
;* These routines take one rectangle and expand it into an internal   *
;* bitmap.                                                            *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       EAX  -> next byte which will need processing
;* Error Returns:
;*       EAX = 0 if data was in unexpected form (probably corrupt)
;*       Error Logged
;* Registers Preserved:
;*       ESI,EDI,EBX,EBP,DS,ES,FS,GS
;* Registers Destroyed:
;*       EAX,ECX,EDX,FLAGS
;* History:
;*
;* Wed 22-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
Planar4bppRectangle PROC SYSCALL USES edi esi,
        pBuffer :DWORD,
        pBitmap :DWORD,
        prcl    :DWORD

LOCAL   cbScanDelta :DWORD,
        cScansToDo :DWORD,
        cUnitsToDo :DWORD,
        cUnitsPerScan :DWORD,
        pLastScanline :DWORD,
        pLastBut1Scanline :DWORD,
        cbEndOfScanInc :DWORD

        ProcessOneRectangle_body planar
        ret

Planar4bppRectangle ENDP

;**********************************************************************

ALIGN 4
Packed4bppRectangle PROC SYSCALL USES edi esi,
        pBuffer :DWORD,
        pBitmap :DWORD,
        prcl    :DWORD

LOCAL   cbScanDelta :DWORD,
        cScansToDo :DWORD,
        cUnitsToDo :DWORD,
        cUnitsPerScan :DWORD,
        pLastScanline :DWORD,
        pLastBut1Scanline :DWORD,
        cbEndOfScanInc :DWORD,
        pPlanar :DWORD,
        cPels :DWORD

        ProcessOneRectangle_body packed_4
        ret

Packed4bppRectangle ENDP

;**********************************************************************

ALIGN 4
InvalidFormat PROC SYSCALL USES edi esi
        int     3
        ret

InvalidFormat ENDP

;/*
;** We have a table of rectangle processing routines.
;** There is a different routine for each of the possible compressed
;** formats that we may be passed.
;*/
ALIGN 4
RectProcessingTable:
        DWORD  Packed4bppRectangle     ; format word = 0
        DWORD  InvalidFormat           ; format word = 1
        DWORD  InvalidFormat           ; format word = 2
        DWORD  InvalidFormat           ; format word = 3
        DWORD  InvalidFormat           ; format word = 4
        DWORD  InvalidFormat           ; format word = 5
        DWORD  InvalidFormat           ; format word = 6
        DWORD  InvalidFormat           ; format word = 7
        DWORD  Planar4bppRectangle     ; format word = 8

        .erre  (GSB_OPT_4BPP + GSB_OPT_LINEAR)  eq 0
        .erre  (GSB_OPT_8BPP + GSB_OPT_LINEAR)  eq 1
        .erre  (GSB_OPT_16BPP + GSB_OPT_LINEAR) eq 2
        .erre  (GSB_OPT_4BPP + GSB_OPT_PLANAR)  eq 8



;--------------------------Internal-Routine-----------------------------;
;/*********************************************************************
;* DecompressScreenBits                                               *
;*                                                                    *
;* This routine takes the output from GetScreenBits and builds a      *
;* replica image into a bitmap, within the same area that was         *
;* originally recorded, allowing for format conversion.               *
;*                                                                    *
;* The VGA driver will only ever be passed 4bpp data.                 *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       EAX  = TRUE (1)
;* Error Returns:
;*       EAX  = FALSE (0)
;*       Error logged
;* Registers Preserved:
;*       ESI,EDI,EBX,EBP
;* Registers Destroyed:
;*       EAX,ECX,EDX,FLAGS
;* History:
;*
;* Wed 22-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
DecompressScreenBits PROC SYSCALL USES edi esi,
        hddc    :DWORD,
        hrgn    :DWORD,
        pBuffer :DWORD

LOCAL   pEnd    :DWORD,
        pBitmap :DWORD,
        rclLocal :RECTL,
        pfnProcess :DWORD

;/*
;** Let's get access to the actual data
;*/
        mov     edi, pBuffer
        ASSUME  EDI:PTR PACKETHDR

;/*
;** Calculate the data end
;*/
        mov     eax, [edi].phd_length
        add     eax, edi
        dec     eax             ; last byte used is start + length - 1
        mov     pEnd, eax

;/*
;** Find the format of this data.
;** The (device specific) higher entry function should check if
;** this device can handle this format.
;*/
        movzx   ebx, [edi].phd_format
        mov     eax, dword ptr RectProcessingTable[ebx*4]   ; dword entries
        mov     pfnProcess, eax

;/*
;** Move to the first rectangle
;*/
        add     edi, size PACKETHDR
        ASSUME  EDI:PTR RealRECTS

;/*
;** Get hold of the bitmap handle from the DC instance.
;*/
        mov     esi, hddc
        ASSUME  ESI:PTR DDC
        mov     esi, [esi].ddc_npsd
        ASSUME  ESI:PTR SURFACE
        mov     pBitmap, esi


each_rectangle:
;/*
;** For this loop we have the following registers
;** edi -> current (incremented) pBuffer value
;** esi -> bitmap (surface) definition
;*/

;/*
;** Check to see if we have got to the end of the buffer
;*/
        or      edi,edi         ; have we processed a full 64K of data ?
        jz      good_exit_relay
        cmp     edi,pEnd        ; have we passed the end of the data ?
        jbe     got_a_rectangle
good_exit_relay:
        jmp     good_exit_now

got_a_rectangle:
;/*
;** Check that the rectangle fits within the bitmap size
;*/
ifdef FIREWALLS
;/*
;** We assume that other code will ensure that all
;** rectangles are positive (since screen bounds must at
;** least be within the screen size!)
;*/
        xor     eax,eax
        cmp     [edi].rcs_xLeft, ax
        jl      invalid_rect
        cmp     [edi].rcs_yBottom, ax
        jl      invalid_rect
endif ;FIREWALLS
        mov     eax, [esi].sd_cx        ; bitmap width
        cmp     ax, [edi].rcs_xRight
        jl      invalid_rect
        mov     eax, [esi].sd_cy        ; bitmap height
        cmp     ax, [edi].rcs_yTop
        jl      invalid_rect

;/*
;** Repack the RealRECTS into a RECTL structure
;*/
        movsx   eax, [edi].rcs_xLeft
        mov     rclLocal.rcl_xLeft, eax
        movsx   eax, [edi].rcs_yBottom
        mov     rclLocal.rcl_yBottom, eax
        movsx   eax, [edi].rcs_xRight
        mov     rclLocal.rcl_xRight, eax
        movsx   eax, [edi].rcs_yTop
        mov     rclLocal.rcl_yTop, eax

;/*
;** Jump past the rectangle data.
;*/
        add     edi, size RealRECTS

;/*
;** Process this rectangle.
;*/
        INVOKE  PFNProcessRectangle PTR pfnProcess,
                edi,
                esi,
                ADDR rclLocal

        and     eax,eax         ; returns NULL ptr on an error
        je      exit_now

;/*
;** Put the returned pointer back into the registers we require
;*/
        mov     edi, eax

;/*
;** If we were passed a region handle, then we need to update it
;** NB. Will we be passed an option flag to say if this handle is to
;** be used or not ?
;*/
        cmp     hrgn,0
        jz      each_rectangle          ; no region so do the next rectangle

        INVOKE  PFNDefCombineRectRegion PTR pfnDefCombineRectRegion,
                0,             ; hdc
                hrgn,
                ADDR rclLocal, ; prcl
                hrgn,
                CRGN_OR,
                hddc,
                NGreCombineRectRegion

        .errnz  RGN_ERROR
        and     eax,eax
        jnz     each_rectangle

        jmp     exit_now

invalid_rect:
        mov     eax, PMERR_INV_RECT
        save_error_code
        xor     eax,eax

good_exit_now:
;/*
;** Return success
;*/
        mov     eax, 1
exit_now:
        ret

DecompressScreenBits ENDP

endif ; DCAF

end
