;*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 = CELLCP.ASM
;*
;* DESCRIPTIVE NAME = managing code pages and their mapping vectors. 
;*
;*
;* VERSION      V2.0
;*
;* DATE         01/26/87
;*
;* DESCRIPTION  The code in this file takes care of coercing code page    
;*              ids to usable values and constructing mapping vectors     
;*              for converting code points to glyph points.               
;*
;* FUNCTIONS    Public:   Format_CP_Map
;*                        Get_CP_MAP
;*                        Force_Valid_CP
;*
;* 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/20/88                     ronm - Converted from CellInit.asm
;*   09/09/87                     ronm - Extracted from CellBlt.asm 
;*                                to cure an out-of-memory problem during
;*                                the Make process.
;*
;*****************************************************************************/

        .286c                   ; To allow non-privileged 286 instructions

        .xlist
        include cmacros.inc
INCL_DOS        equ     1
INCL_WINP_MISC  equ     1
        include pmgre.inc
        include driver.inc
        include njmp.mac
        .list

        ??_out  cellcp


DEFAULT_CP      equ     850


;;;;;;;;;;;;;;;;; Code Page Mapping Chains ;;;;;;;;;;;;;;;;;;;;;;;;;;

sBegin  Data

;/*
;** We keep a singly linked list of the code page mapping vectors we've
;** constructed thus far.  The vector for the default Vio code page is
;** at the end of the list.
;*/

CODEPAGEINFO struc
    cpinfo_np_next  dw  ?
    cpinfo_id_cp    dw  ?
    cpinfo_map_cp   dw  256 dup (?)
CODEPAGEINFO ends

        np_cpinfo_first dw  0

        externD hLocalHeap
        externW default_vio_cpid

        externD lpfnGetDBCSEv
sEnd    Data

sBegin  InstanceData
        externW hModDosNls
sEnd    InstanceData

sBegin  Ring3Code
        externFP    ring3_LoadDosNls
sEnd    Ring3Code

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



sBegin  VioSeg
        assumes cs,VioSeg

        externFP    DosCallback
        externFP    WinLoadCharXlateTbl ;Load code page mapping info
        externFP    WinAllocMem
        externFP    WinFreeMem
        externW     VioSegData

staticD ring3_LoadNls,ring3_LoadDosNls
page

;/***************************************************************************
;*
;* FUNCTION NAME = Format_CP_Map
;*
;* DESCRIPTION   = This routine generates a simple code page mapping vector      
;*                 from the character ranges given in a CHARXLATETBL.  The       
;*                 resulting map is a vector containing 256 words with word      
;*                 i defining the proper glyph index for code point i.           
;*                                                                               
;*                 A result of 0 means that the mapping vector was successfully  
;*                 constructed. A result of 1 is returned when the set of        
;*                 character ranges in the given CHARXLATETBL is empty.          
;*                                                                               
;*                 Warnings: The memory for the map is presumed to be allocated  
;*                           and referenced by npmapcp.  That area is strongly   
;*                           presumed to be 256 words long.                      
;*
;* INPUT         = None
;* OUTPUT        = None
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

cProc   Format_CP_Map,<NEAR,PUBLIC>,<bx,cx,dx,si,di,ds,es>
        parmW   npmapcp
        parmD   pchar_xlate_tbl

        localW  cnt_char_ranges
        localW  np_next_char_range

cBegin

;/*
;** Clear the mapping vector to all zeros.
;*/
        mov     es,VioSegData
        mov     di,npmapcp
        mov     dx,di
        cld
        xor     ax,ax
        mov     cx,256
        rep     stosw

;/*
;** Set up my control variables.
;*/
        lds     bx,pchar_xlate_tbl
        mov     cx,chxl_cCharRanges[bx]
        jcxz    null_map
        mov     si,chxl_offCharTbl[bx]
        mov     bx,cx

next_cp_range:

        or      bx,bx                  ; Any char ranges left?
        jz      map_completed
        dec     bx

        mov     di,chtb_wCharLow[si]
        mov     cx,chtb_wCharHigh[si]
        inc     cx
        sub     cx,di
        shl     di,1
        add     di,dx
        lea     si,chtb_rgGlyphs[si]
        rep     movsw

        jmp     SHORT next_cp_range


null_map:

        mov     ax,1
        jmp     SHORT exit_format_cp_map


map_completed:

        xor     ax,ax


exit_format_cp_map:

cEnd

page

;/***************************************************************************
;*
;* FUNCTION NAME = Format_CP_Map
;*
;* DESCRIPTION   = This routine attempts to return the DS relative offset    
;*                 of a code page mapping vector (a vector of 256 words      
;*                 where word i contains the glyph index for code point i    
;*                 of the given code page).  It first consults a list of     
;*                 previously constructed mapping vectors.  If it can't      
;*                 find the requested map, it tries to construct one and     
;*                 add it to the list. If both attempts fail, 0 is returned. 
;*
;* INPUT         = idcp is codepage which we want the map 
;* OUTPUT        = None
;*
;* RETURN-NORMAL = AX - 0 if no map            
;* RETURN-ERROR  = AX - npCPMap if map exists. 
;*
;**************************************************************************/

CDBCSBUF equ 10

cProc   Get_CP_Map,<FAR,PUBLIC>,<bx,dx,si,ds>
        parmW   idcp

        localD  pcharxlatetbl
        localV  cc,%(size COUNTRYCODE)
        localV  chbuf,CDBCSBUF


cBegin

        mov     ds,VioSegData
        assumes ds,Data

        mov     si,np_cpinfo_first
        mov     ax,idcp

examine_next_cp_info_block:

        or      si,si
        jz      not_in_the_cp_info_chain

        cmp     cpinfo_id_cp[si],ax
        njz     found_the_cp_map

        mov     si,cpinfo_np_next[si]
        jmp     SHORT examine_next_cp_info_block


not_in_the_cp_info_chain:

;/*
;** We haven't seen that code page before.  We'll try to load its mapping
;** information via WinLoadCharXlateTbl.
;*/

;/*
;** Test if it is a codepage recognized by the base
;*/
        mov     cc.ctryc_country,0
        mov     cc.ctryc_codepage,ax

        mov     ax,InstanceDataBASE
        mov     es,ax

        cmp     es:hModDosNls,0
        jnz     @F

        save    <ds>
        cCall   DosCallback,<ring3_LoadNls>
        mov     es:hModDosNls,dx
@@:
        lea     ax,cc
        farPtr  lpcc,ss,ax
        lea     bx,chbuf
        farPtr  lpchbuf,ss,bx
        cCall   lpfnGetDBCSEv,<CDBCSBUF,lpcc,lpchbuf>

;/*
;** Check if CodePage is DBCS, if yes then its not supported either
;*/
        or      byte ptr chbuf[1],0
        jnz     cp_not_found

        mov     ax,idcp
        farPtr  null_hab,0,0

        cCall   WinLoadCharXlateTbl,<null_hab,-1,idcp>
        mov     bx,ax
        or      bx,dx
        jz      cp_not_found

        mov     pcharxlatetbl.off,ax
        mov     pcharxlatetbl.sel,dx

        cCall   WinAllocMem,<hLocalHeap,(SIZE CODEPAGEINFO)>
        or      ax,ax
        jz      cp_not_found

        mov     si,ax
        lea     ax,cpinfo_map_cp[si]
        cCall   Format_CP_Map,<ax,pcharxlatetbl>
        or      ax,ax
        jz      map_constructed

        cCall   WinFreeMem,<hLocalHeap,si,(SIZE CODEPAGEINFO)>


cp_not_found:

        xor     ax,ax
        jmp     exit_Get_CP_Map


map_constructed:

;/*
;** Now that we've constructed the mapping vector for the new code page
;** we label it with the code page id and insert it into the chain of
;** code page maps.
;*/

        mov     ax,idcp
        mov     cpinfo_id_cp[si],ax
        mov     ax,np_cpinfo_first
        mov     cpinfo_np_next[si],ax
        mov     np_cpinfo_first,si


found_the_cp_map:
;/*
;** The address we return points to the mapping vector and ignores the
;** structure prefix.
;*/
        lea     ax,cpinfo_map_cp[si]


exit_Get_CP_Map:

cEnd

page


;/***************************************************************************
;*
;* FUNCTION NAME = Force_Valid_CP
;*
;* DESCRIPTION   = This routine attempts to coerce the code page     
;*                 variable denoted by *pcpid to a usable code page. 
;*                 In this context a code page is usable if we can   
;*                 retrieve its mapping vector via Get_CP_Map.  If   
;*                 the given code page is unusable, we substitute the
;*                 default code page, which will always be the last  
;*                 code page in the chain of mapping vectors.        
;*                                                                   
;*                 The explicit result will be 1 if no usable code   
;*                 page can be found and zero otherwise.  When the   
;*                 coercion succeeds, *pmapcp will be set to the     
;*                 VioSegData relative address of the corresponding  
;*                 mapping vector.                                   
;*
;* INPUT         = pcpid - pointer to codepage to try to validate 
;* OUTPUT        = pmapcp - codepoint mapping for *pcpid          
;*
;* RETURN-NORMAL = None
;* RETURN-ERROR  = None
;*
;**************************************************************************/

cProc   Force_Valid_CP,<NEAR,PUBLIC>,<bx,si,ds>
        parmD   pcpid
        parmD   pmapcp

cBegin

        lds     bx,pcpid

        cCall   Get_CP_Map,<[bx]>
        or      ax,ax
        jnz     found_cp_map

        mov     ax,[bx]                     ;       This block of code
        mov     ds,VioSegData               ;       is incorrect.  If the
        mov     si,np_cpinfo_first          ;       codpage requested is
        or      si,si                       ;       erroneous, we should
        jnz     next_cp_info_block          ;       return an error, not
                                            ;       set the codepage to '850'!
        lds     bx,pcpid                    ;       850 may not even be valid as
        mov     [bx],DEFAULT_CP             ;       the system default

        cCall   Get_CP_Map,<default_vio_cpid>
        lds     bx,pmapcp
        mov     [bx],ax

        mov     ax,1
        jmp     SHORT exit_Force_Valid_CP


next_cp_info_block:

        cmp     cpinfo_id_cp[si],ax
        jz      got_a_matching_cp_map

        mov     bx,cpinfo_np_next[si]
        or      bx,bx
        jz      not_in_the_cp_chain

        mov     si,bx
        jmp     SHORT next_cp_info_block


not_in_the_cp_chain:

        mov     ax,cpinfo_id_cp[si]
        lds     bx,pcpid
        mov     [bx],ax


got_a_matching_cp_map:

        lea     ax,cpinfo_map_cp[si]


found_cp_map:

        lds     bx,pmapcp
        mov     [bx],ax
        xor     ax,ax

exit_Force_Valid_CP:

cEnd

sEnd    VioSeg
end
