windows-nt/Source/XPSP1/NT/base/mvdm/wow16/user/winlang.asm

722 lines
25 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
;++
;
; WOW v1.0
;
; Copyright (c) 1991, Microsoft Corporation
;
; WINLANG.ASM
; Win16 language-dependent string services
;
; History:
;
; Created 18-Jun-1991 by Jeff Parsons (jeffpar)
; Copied from WIN31 and edited (as little as possible) for WOW16
;--
;****************************************************************************
;* *
;* WinLang.ASM - *
;* *
;* API calls to support different lanuages *
;* *
;****************************************************************************
NOTEXT = 1
.xlist
include user.inc
.list
ExternFP AllocSelector
ExternFP FreeSelector
ExternFP PrestoChangoSelector
ExternNP IAnsiPrev
ExternNP IAnsiNext
;****************************************************************************
;* *
;* WOW note: The implementations in this file are the US implementations *
;* with all the language driver and DBCS stuff ripped out. *
;* PatchUserStrRtnsToThunk, at the bottom of this file, is *
;* called during startup of user16 if the locale is other *
;* than U.S. English, or if forced to thunk by a registry key. *
;* This routine patches each of the APIs implemented here to *
;* simply jump to the thunk, with a name beginning "Win32". *
;* *
;* The StrRtnsPatchTable defined below controls the patching. *
;* *
;****************************************************************************
ExternNP Win32lstrcmp
ExternNP Win32lstrcmpi
ExternNP Win32AnsiPrev
ExternNP Win32AnsiNext
ExternNP Win32AnsiUpper
ExternNP Win32AnsiLower
ExternNP Win32AnsiUpperBuff
ExternNP Win32AnsiLowerBuff
ExternNP Win32IsCharAlpha
ExternNP Win32IsCharAlphaNumeric
ExternNP Win32IsCharUpper
ExternNP Win32IsCharLower
sBegin DATA
LabelW StrRtnsPatchTable
; Location of patch Target of jmp patched in
; ----------------- ------------------------
dw codeOffset Ilstrcmp, codeOffset Win32lstrcmp
dw codeOffset Ilstrcmpi, codeOffset Win32lstrcmpi
;
; These two functions need to be thunked only for DBCS builds
;
ifdef FE_SB
dw codeOffset IAnsiPrev, codeOffset Win32AnsiPrev
dw codeOffset IAnsiNext, codeOffset Win32AnsiNext
endif ; FE_SB
dw codeOffset IAnsiUpper, codeOffset Win32AnsiUpper
dw codeOffset IAnsiLower, codeOffset Win32AnsiLower
dw codeOffset IAnsiUpperBuff, codeOffset Win32AnsiUpperBuff
dw codeOffset IAnsiLowerBuff, codeOffset Win32AnsiLowerBuff
dw codeOffset IsCharAlpha, codeOffset Win32IsCharAlpha
dw codeOffset IsCharAlphaNumeric, codeOffset Win32IsCharAlphaNumeric
dw codeOffset IsCharUpper, codeOffset Win32IsCharUpper
dw codeOffset IsCharLower, codeOffset Win32IsCharLower
LabelW StrRtnsPatchTableEnd
sEnd
createSeg _TEXT, CODE, WORD, PUBLIC, CODE
sBegin CODE
assumes CS, CODE
assumes DS, DATA
ExternNP MyUpper
ExternNP MyLower
ExternNP MyAnsiUpper
ExternNP MyAnsiLower
;--------------------------------------------------------------------------
;
; The following table contains the primary and secondary weight info.
;
; For alphanumeric characters primary weight is equal to (Ascii + PrimeWt)
; Secondary weight is either 0 or 1 (For all upper case letters zero and
; lower case letters 1);
;
; For non-alphanumeric characters, primary weight is their ASCII value and
; the secondary weight is zero.
;
; Note that the primary weight calculated with this table for the smallest
; of the alpha-numeric character('0') is 100h (30h+D0h), which is more than
; the primary weight of the highest non-alpha-numeric character FFh;
; Thus all non-alpha-numeric characters will sort before any alpha-numeric
; characters;
;
; Note that 'PrimeWt' field for lowercase letters is B0h instead of
; D0h because when added with their ascii, it should become exactly
; equal to the primary weights of their upper-case counterparts;
;
; IMPORTANT NOTE: On 01-17-90, we came across a bug in lstrcmpi() due to
; the fact that we are not treating characters C0h to FEh as upper and
; lower case alphas; So, I added some more ranges to the SortStruc table
; to map the range C0h to D6h onto the range E0h to F6 and to map the
; range D8h to DEh onto the range F8h to FEh. A value of 20h in the PrimeWt
; field automatically takes care of this mapping because that is the diff
; to be added to the uppercase letter to make it lowercase; The secondary
; weights are as usual 0 for uppercase and 1 for lowercase;
; --Fix for Bug #8222 --01-17-90-- SANKAR --
;--------------------------------------------------------------------------
SortStruct STRUC
StartAscii db ?
EndAscii db ?
PrimeWt db ?
SecondWt db ?
SortStruct ENDS
public SortTable
LabelB SortTable
SortStruct <'0', '9', 0D0h, 0>
SortStruct <'A', 'Z', 0D0h, 0>
SortStruct <'a', 'z', 0B0h, 1>
SortStruct <0C0h, 0D6h, 20h, 0>
SortStruct <0D8h, 0DEh, 20h, 0>
SortStruct <0E0h, 0F6h, 0, 1>
SortStruct <0F8h, 0FEh, 0, 1>
LabelB SortTableEnd
;*----------------------------------------------------------------------*
;* *
;* GetWeightValues() *
;* Input: *
;* AL = character whose weight values are asked for *
;* Output: *
;* AX = Primary weight of the character *
;* BL = Secondary weight of the character *
;*----------------------------------------------------------------------*
public GetWeightValues
GetWeightValues PROC NEAR
xor ah, ah
xor bx, bx ; Index into the table
; Enter the number of entries in the sort table.
mov cx, (SortTableEnd - SortTable)/(SIZE SortStruct)
gwv_loop:
cmp al, byte ptr SortTable[bx].StartAscii
jb gwv_end
cmp al, byte ptr SortTable[bx].EndAscii
jbe gwv_GetWeights
add bx, SIZE SortStruct
loop gwv_loop
jmps gwv_end
gwv_GetWeights:
add al, byte ptr SortTable[bx].PrimeWt
adc ah, 0
mov bl, byte ptr SortTable[bx].SecondWt
gwv_end:
ret
GetWeightValues ENDP
;*--------------------------------------------------------------------------*
;* *
;* lstrcmp(String1, String2) - *
;* *
;* String1 and String2 are LPSTR's to null terminated strings. *
;* *
;* This function returns -1 if String1 sorts before String2, 0 if String1*
;* and String2 have the same sorting and 1 if String2 sorts before *
;* String1. *
;* NOTE: This is case sensitive compare. *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32lstrcmp, aka WU32lstrcmp. *
;* *
;*--------------------------------------------------------------------------*
cProc Ilstrcmp, <FAR, PUBLIC>, <SI, DI>
; ^^^^^^^^ US_lstrcmp assumes SI, DI saved!
ParmD lpStr1
ParmD lpStr2
LocalB SecWeight1 ; Locals used by US_lstrcmp
LocalB SecWeight2
LocalB LocSecWeight
LocalB fCaseSensitive ; Flag indicating whether it is case sensitive or not.
cBegin
mov byte ptr fCaseSensitive, 1 ; Yup! It is case sensitive
call US_lstrcmp
cEnd
;*----------------------------------------------------------------------*
;* *
;* US_lstrcmp *
;* US version of string sort(Case sensitive); *
;* Uses locals defined by Ilstrcmp above.
;* To understand the algorithm, read the comments for SortStruct *
;* *
;*----------------------------------------------------------------------*
public US_lstrcmp
US_lstrcmp PROC NEAR
push ds ; Save ds
;Initialise the secondary wt values
mov byte ptr SecWeight1, 0
mov byte ptr SecWeight2, 0
; Load both the strings
lds si, lpStr1
les di, lpStr2
ss_loop:
; Take one char from both the strings.
mov al, byte ptr ds:[si]
xor ah, ah ; make secondary wts zero
mov dl, byte ptr es:[di]
xor dh, dh
inc si ; Move to next character
inc di
cmp al, 0
jz ss_chkprimary ; Check if lpStr1 has ended
cmp dl, 0
jz ss_chkprimary ; Check if lpStr2 has ended
; Let us compare the ASCII vaues
; If the asciis are equal, then weights are equal
cmp al, dl
je ss_loop ; Goto next character
; Now, the asciis differ. So, let us find the weights
; Let us get the weights for the character of lpStr1 (in ax )
call GetWeightValues
; ax contains the primary weight of char of lpStr1
; bl contains the secondary weight of ditto
mov LocSecWeight, bl
xchg ax, dx
call GetWeightValues
; compare primary weights
; Primary weight of Str1 in DX and Str2 in AX
cmp ax, dx
jb CompareRetGT
ja CompareRetLT
; Check if it is Case-Insensitive compare
mov bh, fCaseSensitive
or bh, bh
jz ss_loop ; It is case-insensitive; So, no need to consider
; the secondary weightages. Goto next character.
; Control comes here only if it is a case sensitive compare.
; Now, primaries are equal. Compare secondaries
mov bh, LocSecWeight
cmp bh, bl
je ss_loop ; Secondaries are equal, Continue
; Secondaries are not equal. Check if they are stored already
mov cl, SecWeight1
or cl, SecWeight2
jnz ss_loop ; Secondaries already exist, continue
; Secondaries haven't been saved sofar.Save the secondaries
mov SecWeight1, bh
mov SecWeight2, bl
jmps ss_loop ; Process the next character
ss_chkprimary:
; al, dl contain the primary weights and at least one of them is
; zero.
cmp al, 0
ja CompareRetGT
cmp dl, 0
ja CompareRetLT
; both are zero; they are equal; So, check the secondary values
mov bl, SecWeight1
cmp bl, SecWeight2
ja CompareRetGT
jb CompareRetLT
; They are identical with equal weightages
xor ax, ax
jmps CompareRet
CompareRetGT:
mov ax, 1
jmps CompareRet
CompareRetLT:
mov ax, -1
CompareRet:
pop ds
ret
US_lstrcmp ENDP
;*--------------------------------------------------------------------------*
;* *
;* lstrcmpi(String1, String2) - *
;* (Case Insensitive compare) *
;* String1 and String2 are LPSTR's to null terminated strings. *
;* *
;* This function returns -1 if String1 sorts before String2, 0 if String1*
;* and String2 have the same sorting and 1 if String2 sorts before *
;* String1. *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32lstrcmpi, aka WU32lstrcmpi. *
;* *
;*--------------------------------------------------------------------------*
cProc Ilstrcmpi, <FAR, PUBLIC>, <SI, DI>
; ^^^^^^^^ US_lstrcmp assumes SI, DI saved!
ParmD lpStr1
ParmD lpStr2
LocalB SecWeight1 ; Locals used by US_lstrcmp
LocalB SecWeight2
LocalB LocSecWeight
LocalB fCaseSensitive ; Flag indicating whether it is case sensitive or not.
cBegin
mov byte ptr fCaseSensitive, 0 ; FALSE => Case-Insensitive.
call US_lstrcmp
cEnd
;*----------------------------------------------------------------------*
;* *
;* AnsiUpper implementation is from Win3.1 US_AnsiUpper() *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32AnsiUpper, aka WU32AnsiUpper. *
;* *
;*----------------------------------------------------------------------*
cProc IAnsiUpper, <FAR, PUBLIC, PASCAL>, <SI, DI>
ParmD lpStr
cBegin
les di,lpStr
mov cx,es
mov ax,di
call MyUpper ; if passed a char, just upper case it.
jcxz au1
inc cx ; take care of the case of sign propagation
jz au1
dec cx
call MyAnsiUpper ; otherwise upper case the whole string
mov ax, word ptr lpStr ; Now, dx:ax points at original string
au1: mov dx,es
cEnd
;*----------------------------------------------------------------------*
;* *
;* AnsiLower implementation is from Win3.1 US_AnsiLower() *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32AnsiLower, aka WU32AnsiLower. *
;* *
;*----------------------------------------------------------------------*
cProc IAnsiLower, <FAR, PUBLIC, PASCAL>, <SI, DI>
ParmD lpStr
cBegin
les di,lpStr
mov cx,es
mov ax,di
call MyLower ; if passed a char, just lower case it.
jcxz al1
inc cx ; take care of the case of sign propagation
jz al1
dec cx
call MyAnsiLower ; otherwise lower case the whole string
mov ax, word ptr lpStr ; dx:ax points at original string
al1: mov dx,es
cEnd
;*----------------------------------------------------------------------*
;* *
;* AnsiUpperBuff implemented from Win3.1 US_AnsiUpperBuff *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32AnsiUpperBuff, aka WU32AnsiUpperBuff. *
;* *
;*----------------------------------------------------------------------*
cProc IAnsiUpperBuff, <FAR, PUBLIC, PASCAL>, <SI, DI>
ParmD lpStr
ParmW iCount
cBegin
cld
les di, lpStr
mov si, di
mov cx, iCount ; if iCount=0, the Buff size is 64K.
mov dx, iCount ; Preserve the length of Buffer
su_begin:
lods byte ptr es:[si]
call MyUpper
stosb
loop su_begin
su_over:
mov ax, dx ; Move the result to ax
cEnd
;*----------------------------------------------------------------------*
;* *
;* AnsiLowerBuff implemented from Win3.1 US_AnsiLowerBuff *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32AnsiLowerBuff, aka WU32AnsiLowerBuff. *
;* *
;*----------------------------------------------------------------------*
cProc IAnsiLowerBuff, <FAR, PUBLIC, PASCAL>, <SI, DI>
ParmD lpStr
ParmW iCount
cBegin
cld
les di, lpStr
mov si, di
mov cx, iCount ; If cx=0, the buff size is 64K
mov dx, cx ; Preserve the length in DX
sl_begin:
lods byte ptr es:[si]
call MyLower
stosb
loop sl_begin
sl_over:
mov ax, dx ; Move the result to ax
cEnd
;*----------------------------------------------------------------------*
;* *
;* IsCharLower implemented with Win3.1 US_IsCharLower *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32IsCharLower, aka WU32IsCharLower. *
;* *
;*----------------------------------------------------------------------*
cProc IsCharLower, <FAR, PUBLIC, PASCAL>
ParmB bChar
cBegin
mov al, bChar
call Loc_Lower
jc icl_end
xor ax, ax ; Not lower. So, false
icl_end:
cEnd
;*----------------------------------------------------------------------*
;* *
;* IsCharUpper implemented with Win3.1 US_IsCharUpper *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32IsCharUpper, aka WU32IsCharUpper. *
;* *
;*----------------------------------------------------------------------*
cProc IsCharUpper, <FAR, PUBLIC, PASCAL>
ParmB bChar
cBegin
mov al, bChar
call Loc_Upper
jc icu_end
xor ax, ax
icu_end:
cEnd
;*----------------------------------------------------------------------*
;* *
;* IsCharAlphaNumeric implemented with Win3.1 US_IsCharAlphaNumeric *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32IsCharAlphaNumeric, aka WU32IsCharAlphaNumeric. *
;* *
;*----------------------------------------------------------------------*
cProc IsCharAlphaNumeric, <FAR, PUBLIC, PASCAL>
ParmB bChar
cBegin
mov al, bChar
call Loc_Numeric
jc ica_end
jmps ica_begin
cEnd
;*----------------------------------------------------------------------*
;* *
;* IsCharAlpha implemented with Win3.1 US_IsCharAlpha *
;* *
;* Outside the U.S. English locale, this function is patched to be a *
;* near jump to Win32IsCharAlpha, aka WU32IsCharAlpha. *
;* *
;*----------------------------------------------------------------------*
cProc IsCharAlpha, <FAR, PUBLIC, PASCAL>
ParmB bChar
cBegin
mov al, bChar
ica_begin:
call Loc_Lower
jc ica_end
call Loc_Upper
jc ica_end
xor ax, ax
ica_end:
cEnd
;*----------------------------------------------------------------------*
;* *
;* Loc_Upper, LocLower, Loc_Numeric *
;* *
;* Used by IsCharXxx US implementations *
;* *
;* Input: *
;* AL = character being tested *
;* Output: *
;* Carry flag set if TRUE *
;* Carry flag cleared if FALSE *
;*----------------------------------------------------------------------*
public Loc_Upper
LabelNP <Loc_Upper>
cmp al, 'A'
jb Loc_False
cmp al, 'Z'
jbe Loc_True
cmp al, 0C0h
jb Loc_False
cmp al, 0D7h ; This is multiply sign in Microsoft fonts, So, ignore;
je Loc_False ; Fix for Bug #1356; SANKAR --08-28-89--;
cmp al, 0DEh
jbe Loc_True
jmps Loc_False
public Loc_Lower
LabelNP <Loc_Lower>
; 0xDF and 0xFF are Lower case. But they don't have an equivalent
; upper case letters;
; So, they are treated as special case chars here
; Fix for Bug # 9799 --SANKAR-- 02-21-90 --
cmp al, 0DFh
je Loc_True
cmp al, 0FFh
je Loc_True
; Fall thro to the next function
errnz ($-Loc_IsConvertibleToUpperCase)
public Loc_IsConvertibleToUpperCase
LabelNP <Loc_IsConvertibleToUpperCase>
cmp al, 'a'
jb Loc_False
cmp al, 'z'
jbe Loc_True
cmp al, 0E0h
jb Loc_False
cmp al, 0F7h ; This is divide sign in Microsoft fonts; So, ignore
je Loc_False; ; Fix for Bug #1356; SANKAR --08-28-89--;
cmp al, 0FEh
jbe Loc_True
jmps Loc_False
LabelNP <Loc_Numeric>
cmp al, '0'
jb Loc_False
cmp al, '9'
ja Loc_False
Loc_True:
stc ; Set carry to indicate true
jmps Loc_End
Loc_False:
clc ; Clear carry to indicate false
Loc_End:
ret
;*----------------------------------------------------------------------*
;* *
;* PatchUserStrRtnsToThunk -- *
;* *
;*----------------------------------------------------------------------*
cProc PatchUserStrRtnsToThunk, <PUBLIC, FAR, PASCAL>, <SI,DI>
cBegin
cCall AllocSelector, <0>
cCall PrestoChangoSelector, <cs, ax>
push ax
pop es
mov si, dataOffset StrRtnsPatchTable ; ds:si = StrRtnsPatchTable
PatchLoop:
lodsw
mov di, ax ; di = offset of code to be patched
mov ax, 0E9h ; opcode for near jump w/2 byte diff.
stosb ; store jmp opcode
lodsw
sub ax, di ; difference between src and target
sub ax, 2 ; encoded difference is based on
; address of next instruction
stosw ; store difference
cmp si, dataOffset StrRtnsPatchTableEnd
jb PatchLoop
xor ax, ax
push es ; for FreeSelector
push ax
pop es
call FreeSelector
cEnd
sEnd CODE
end