;/*static char *SCCSID = "@(#)nlsthk.asm        6.3 92/03/04";*/
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************

;***  Change History						  ***
;***   noto  11/18/93  Define which segment for Page Tuning DLL   ***
;***								  ***


.xlist
include dc1segs.inc
.list
	TITLE	$nlsthk.asm

	.386

;Error codes taken out of error.h

ERROR_NOMEMORY EQU 8

ERROR_INVALIDPARAM EQU 87

PUBLIC	DOS32QUERYCTRYINFO
PUBLIC	DOS32QUERYDBCSENV
PUBLIC	DOS32MAPCASE
PUBLIC	DOS32QUERYCOLLATE

CODE32_TUNE1  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	DOS32ALLOCMEM:NEAR
EXTRN	DOS32FREEMEM:NEAR
EXTRN	THK32FREEBLOCK:NEAR
EXTRN	THK32HANDLESTRING:NEAR
CODE32_TUNE1  ENDS

CODE32_TUNE2  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32ALLOCBLOCK:NEAR
EXTRN	THK32ALLOCVARLEN:NEAR
EXTRN	THK32DEALLOC:NEAR
CODE32_TUNE2  ENDS

CODE32_TUNE4  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32FREEALIAS:NEAR
EXTRN	THK32HANDLEBOUNDARY:NEAR
CODE32_TUNE4  ENDS

CODE32	SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32ALIASMEM:NEAR
EXTRN	THK32ALLOCSTACK:NEAR
EXTRN	THK32FREESTACK:NEAR
CODE32	ENDS

DATA32	SEGMENT
DATA32	ENDS

EXTRN	DOSGETCTRYINFO:FAR
EXTRN	DOSGETDBCSEV:FAR
EXTRN	DOSCASEMAP:FAR
EXTRN	DOSGETCOLLATE:FAR


CODE16C_TUNE2 SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C_TUNE2 ENDS

CODE16C SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C ENDS




;Create a dummy label to trick MASM into correct fixups

CODE16C SEGMENT

T_DOSGETCTRYINFO	LABEL FAR

CODE16C ENDS


CODE32	SEGMENT
	ASSUME CS:FLAT,DS:FLAT,ES:FLAT
DOS32QUERYCTRYINFO PROC

	push	ebp
	mov	ebp,esp


	cld			;Assume direction flag clear
	xor	eax,eax
	push	eax		; temp storage for return value
	push	esi
	push	edi
	push	eax		; temp storage
	push	eax		;Error flag for cleanup
	push	eax		; temp storage for Stack Allocation Flags
	push	eax		; temp storage for BMP Flags
	push	eax		; temp storage for Alias Flags
	push	eax		; temp storage for ptr param #1
	push	eax		; temp storage for ptr param #2
	push	eax		; temp storage for ptr param #3
;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

	push	0000			;push for stack comparison later
	mov	eax,ss
	cmp	ax,seg FLAT:DATA32		; standard 32 bit stack?
	jne	short L1		; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

	mov	eax,esp
	cmp	ax,1024
	jae	short L1
	pop	ecx			;old stack comparator
	call	THK32ALLOCSTACK 	; bump the stack down
	push	eax			;old stack comparator on old stack
	mov	esp,eax


;Insure that 1 DWORD exists on stack
	push	eax
L1:


; ****> BEGIN Pointer/Structure Section



	mov	esi,[ebp+12]		; base address

;Pointer  --> datain
	or	esi,esi
	jz	L2

	mov	[ebp-36],esi

;Structures are not Identical
;Structures don't have pointers

; Allocate space on stack
	sub	esp,4			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-36],edi
;Copy structure to new area


;Element country --> country

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOUNTRYINFO

	mov	WORD PTR [edi],ax

;Element codepage --> codepage

;Adjust registers after conversion
	add	esi,4
	add	edi,2

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOUNTRYINFO

	mov	WORD PTR [edi],ax

L2:


	mov	esi,[ebp+16]		; base address

;Pointer  --> dataout
	or	esi,esi
	jz	L3

	mov	[ebp-40],esi

;Structures are not Identical
;Structures don't have pointers

;Need block allocation
;Generate Allocation Call
	call	Thk32AllocBlock
	or	eax,eax
	jnz	NOMEM_DOS32QUERYCOUNTRYINFO

	mov	[ebp-40],edi

L3:


	mov	esi,[ebp+20]		; base address

;Pointer  --> datalen
	or	esi,esi
	jz	L4

	mov	[ebp-44],esi

;Have PU/LONG, want PU/SHORT
;Use the LONG as buffer, only if it doesn't
;cross boundary

;Check Boundary Crossing - fixed size item
	cmp	si,65532
	jbe	L4			;Enough room

; Allocate space on stack
	sub	esp,2			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-44],edi

L4:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

	push	es
	push	ebx			; save ebx
	push	ebp			; save ebp
	mov	eax,esp 		; save current esp
	push	ss
	push	eax


	mov	dx,ss			; get cpl bits to use as dpl bits
	and	dx,3			; mask off rest of register

	or	dl,4			;Force LDT bit on


	;From Name:   Type: unsigned long
	mov	eax,[ebp+8]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOUNTRYINFO

	push	ax		;To:unsigned short


	;From Name:   Type: struct COUNTRYCODE
	mov	eax,DWORD PTR [ebp-36]
	or	eax,eax
	jz	short L5			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L5:	push	eax



	;From Name:   Type: struct COUNTRYINFO
	mov	eax,DWORD PTR [ebp-40]
	or	eax,eax
	jz	short L6			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L6:	push	eax



	;From Name:   Type: unsigned long
	mov	eax,DWORD PTR [ebp-44]
	or	eax,eax
	jz	short L7			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L7:	push	eax


;* Convert SS:ESP to 16-bit SS:SP.

	mov	eax,esp 		; use CRMA on ESP
	ror	eax,16
	shl	ax,3
	or	al,dl
	rol	eax,16

	push	eax			; push new stack pointer
	lss	sp,DWORD PTR [esp]	; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

	jmp	FAR PTR T_DOSGETCTRYINFO


INVP_DOS32QUERYCOUNTRYINFO:
	push	ERROR_INVALIDPARAM
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L8

ERR_DOS32QUERYCOUNTRYINFO:
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L8

NOMEM_DOS32QUERYCOUNTRYINFO:
	push	ERROR_NOMEMORY
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L8
R_DOSGETCTRYINFO:				; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

	movzx	esp,sp			; make sure that esp is correct
	lss	esp,[esp]
	pop	ebp
	pop	ebx
	pop	es



;Convert Return Code
;USHORT --> ULONG
	movzx	eax,ax
L8:
;Functions contain pointers, save return code
	mov	[ebp-4],eax		;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> datain


	mov	esi,[ebp-36]		; temp address
	or	esi,esi
	jz	L9



	mov	edi,[ebp+12]		; original address

;Structures are not Identical
;Structures don't have pointers
;Structure doesn't have output semantics
;Return structure to original area

;Deallocate Temporary Structure


;Stack allocated memory deallocated implicitly

L9:		;No action required

;Undo Pointer  --> dataout


	mov	esi,[ebp-40]		; temp address
	or	esi,esi
	jz	L10



	mov	edi,[ebp+16]		; original address

;Structures are not Identical
;Structures don't have pointers
;Structure has output semantics
;Return structure to original area


	test	BYTE PTR[ebp-20],1		;Check for errors D
	jnz	L11			;No copy if error

;Element country --> country

;USHORT --> ULONG
;Copy 4 bytes if receiving buffer at least 4 bytes
	cmp	DWORD PTR [ebp+8],4
	jb	COPYEND
	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

;Element codepage --> codepage

;Adjust registers after conversion
	add	esi,2
	add	edi,4

;USHORT --> ULONG
;Copy 4 bytes if receiving buffer at least 8 bytes
	cmp	DWORD PTR [ebp+8],8
	jb	COPYEND
	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

;Element fsDateFmt --> fsDateFmt

;Adjust registers after conversion
	add	esi,2
	add	edi,4

;USHORT --> ULONG
;Copy 4 bytes if receiving buffer at least 12 bytes
	cmp	DWORD PTR [ebp+8],12
	jb	COPYEND
	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

;Element szCurrency --> szCurrency

;Adjust registers after conversion
	add	esi,2
	add	edi,4

;Copy 5 bytes if receiving buffer at least 17 bytes
	cmp	DWORD PTR [ebp+8],17
	jb	COPYEND
	mov	ecx,5
	rep	movsb

;Element szThousandsSeparator --> szThousandsSeparator
;Copy 2 bytes if receiving buffer at least 19 bytes
	cmp	DWORD PTR [ebp+8],19
	jb	COPYEND
	movsw

;Element szDecimal --> szDecimal
;Copy 2 bytes if receiving buffer at least 21 bytes
	cmp	DWORD PTR [ebp+8],21
	jb	COPYEND
	movsw

;Element szDateSeparator --> szDateSeparator
;Copy 2 bytes if receiving buffer at least 23 bytes
	cmp	DWORD PTR [ebp+8],23
	jb	COPYEND
	movsw

;Element szTimeSeparator --> szTimeSeparator
;Copy 2 bytes if receiving buffer at least 25 bytes
	cmp	DWORD PTR [ebp+8],25
	jb	COPYEND
	movsw

;Element fsCurrencyFmt --> fsCurrencyFmt
;Copy 1 byte if receiving buffer at least 26 bytes
	cmp	DWORD PTR [ebp+8],26
	jb	COPYEND
	movsb

;Element cDecimalPlace --> cDecimalPlace
;Copy 1 byte if receiving buffer at least 27 bytes
	cmp	DWORD PTR [ebp+8],27
	jb	COPYEND
	movsb

;Element fsTimeFmt --> fsTimeFmt
;Copy 1 byte if receiving buffer at least 28 bytes
	cmp	DWORD PTR [ebp+8],28
	jb	COPYEND
	movsb

;Element abReserved1 --> abReserved1
;Copy 4 bytes if receiving buffer at least 32 bytes
	cmp	DWORD PTR [ebp+8],32
	jb	COPYEND
	movsd

;Element szDataSeparator --> szDataSeparator
;Copy 2 bytes if receiving buffer at least 34 bytes
	cmp	DWORD PTR [ebp+8],34
	jb	COPYEND
	movsw

;Element abReserved2 --> abReserved2
;Copy 10 bytes if receiving buffer at least 44 bytes
	cmp	DWORD PTR [ebp+8],44
	jb	COPYEND
	mov	ecx,5
	rep	movsw

COPYEND:

L11:			;ErrorLabel D
;Deallocate Temporary Structure

;Need block dallocation
	mov	esi,[ebp-40]
	call	Thk32FreeBlock


L10:		;No action required

;Undo Pointer  --> datalen


	mov	esi,[ebp-44]		; temp address
	or	esi,esi
	jz	L12



	mov	edi,[ebp+20]		; original address

;This item is either on the stack, or is still
;in its original position.
;Output semantics convert in place

	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

L12:		;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

	lea	esp,[ebp-48]	; get the old stack
	pop	ecx			;get the new stack
	cmp	ecx,0			;is it new
	jz	@f
	call	THK32FREESTACK		;deallocate the memory
@@:
	lea	esp,[ebp-12]
	pop	edi
	pop	esi
	pop	eax		;Pop saved return code
	leave
	ret				; Remove parameters

DOS32QUERYCTRYINFO endp

CODE32	ENDS

;* 16-bit code to make API call.

CODE16C SEGMENT

	ASSUME CS:CODE16C
	.errnz ($ - T_DOSGETCTRYINFO)

	call	FAR PTR DOSGETCTRYINFO		; call 16-bit version
	jmp	FAR PTR FLAT:R_DOSGETCTRYINFO		; jump back

CODE16C ENDS


;Create a dummy label to trick MASM into correct fixups

CODE16C_TUNE2 SEGMENT

T_DOSGETDBCSEV	LABEL FAR

CODE16C_TUNE2 ENDS


CODE32_TUNE2  SEGMENT
	ASSUME CS:FLAT,DS:FLAT,ES:FLAT
DOS32QUERYDBCSENV PROC

	push	ebp
	mov	ebp,esp


	cld			;Assume direction flag clear
	xor	eax,eax
	push	eax		; temp storage for return value
	push	esi
	push	edi
	push	eax		; temp storage
	push	eax		;Error flag for cleanup
	push	eax		; temp storage for Stack Allocation Flags
	push	eax		; temp storage for BMP Flags
	push	eax		; temp storage for Alias Flags
	push	eax		; temp storage for ptr param #1
	push	eax		; temp storage for ptr param #2

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

	push	0000			;push for stack comparison later
	mov	eax,ss
	cmp	ax,seg FLAT:DATA32		; standard 32 bit stack?
	jne	short L14		; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

	mov	eax,esp
	cmp	ax,1024
	jae	short L14
	pop	ecx			;old stack comparator
	call	THK32ALLOCSTACK 	; bump the stack down
	push	eax			;old stack comparator on old stack
	mov	esp,eax


;Insure that 1 DWORD exists on stack
	push	eax
L14:


; ****> BEGIN Pointer/Structure Section



	mov	esi,[ebp+12]		; base address

;Pointer  --> datain
	or	esi,esi
	jz	L15

	mov	[ebp-36],esi

;Structures are not Identical
;Structures don't have pointers

; Allocate space on stack
	sub	esp,4			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-36],edi
;Copy structure to new area


;Element country --> country

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYDBCSENV

	mov	WORD PTR [edi],ax

;Element codepage --> codepage

;Adjust registers after conversion
	add	esi,4
	add	edi,2

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYDBCSENV

	mov	WORD PTR [edi],ax

L15:


	mov	esi,[ebp+16]		; base address

;Pointer  --> dataout
	or	esi,esi
	jz	L16

	mov	[ebp-40],esi
	mov	ecx,[ebp+8]		;Get Size Parameter
	or	ecx,ecx
	jz	L16		;Nothing to check

;DWORD --> WORD sized length. Error if Size > 64k
	cmp	ecx,10000h
	jae	INVP_DOS32QUERYDBCSENV			;jmp if too long
;ECX holds size in bytes

;Check Boundary Crossing
	mov	eax,esi
	neg	ax
	jz	L16			;0=full 64k of room

	cmp	ax,cx
	jae	L16			;Enough room

	call	Thk32HandleBoundary
	or	eax,eax
	jnz	NOMEM_DOS32QUERYDBCSENV 		;
	mov	[ebp-40],edi
	or	edx,edx
	js	short L17		;Alloced Mem
	or	BYTE PTR [ebp+(edx*4)-32],2		;Set Flag

L17:			;Variable Length Copy

;Item semantics are NOT input

L18:			;Variable Length No Copy

L16:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

	push	es
	push	ebx			; save ebx
	push	ebp			; save ebp
	mov	eax,esp 		; save current esp
	push	ss
	push	eax


	mov	dx,ss			; get cpl bits to use as dpl bits
	and	dx,3			; mask off rest of register

	or	dl,4			;Force LDT bit on


	;From Name:   Type: unsigned long
	mov	eax,[ebp+8]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYDBCSENV

	push	ax		;To:unsigned short


	;From Name:   Type: struct COUNTRYCODE
	mov	eax,DWORD PTR [ebp-36]
	or	eax,eax
	jz	short L19			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L19:	push	eax



	;From Name:   Type: char
	mov	eax,DWORD PTR [ebp-40]
	or	eax,eax
	jz	short L20			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L20:	push	eax


;* Convert SS:ESP to 16-bit SS:SP.

	mov	eax,esp 		; use CRMA on ESP
	ror	eax,16
	shl	ax,3
	or	al,dl
	rol	eax,16

	push	eax			; push new stack pointer
	lss	sp,DWORD PTR [esp]	; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

	jmp	FAR PTR T_DOSGETDBCSEV


INVP_DOS32QUERYDBCSENV:
	push	ERROR_INVALIDPARAM
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L21

ERR_DOS32QUERYDBCSENV:
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L21

NOMEM_DOS32QUERYDBCSENV:
	push	ERROR_NOMEMORY
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L21
R_DOSGETDBCSEV: 			; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

	movzx	esp,sp			; make sure that esp is correct
	lss	esp,[esp]
	pop	ebp
	pop	ebx
	pop	es



;Convert Return Code
;USHORT --> ULONG
	movzx	eax,ax
L21:
;Functions contain pointers, save return code
	mov	[ebp-4],eax		;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> datain


	mov	esi,[ebp-36]		; temp address
	or	esi,esi
	jz	L22



	mov	edi,[ebp+12]		; original address

;Structures are not Identical
;Structures don't have pointers
;Structure doesn't have output semantics
;Return structure to original area

;Deallocate Temporary Structure


;Stack allocated memory deallocated implicitly

L22:		;No action required

;Undo Pointer  --> dataout


	mov	esi,[ebp-40]		; temp address
	or	esi,esi
	jz	L23



	mov	edi,[ebp+16]		; original address
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
	cmp	esi,edi
	je	L23

	test	BYTE PTR[ebp-20],1		;Check for errors A
	jnz	L24			;No copy if error

;Get size for copy out
	mov	ecx,[ebp+8]		;Get Size
;ECX holds size in bytes

;If aliased, then skip over possible copyout
	test	BYTE PTR[ebp-32],2		;Test Alias Flag
	jnz	L25
;Copy out ecx bytes
	push	esi		;Save ptr to temp object

; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK
	pop	esi		;Get ptr to temp object
L25:			;Aliased Label
	push	-32		;Alloc Flag Offset
	mov	edx,2

	call	THK32DEALLOC



L24:			;ErrorLabel A

L23:		;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

	lea	esp,[ebp-44]	; get the old stack
	pop	ecx			;get the new stack
	cmp	ecx,0			;is it new
	jz	@f
	call	THK32FREESTACK		;deallocate the memory
@@:
	lea	esp,[ebp-12]
	pop	edi
	pop	esi
	pop	eax		;Pop saved return code
	leave
	ret				; Remove parameters

DOS32QUERYDBCSENV endp

CODE32_TUNE2  ENDS

;* 16-bit code to make API call.

CODE16C_TUNE2 SEGMENT

	ASSUME CS:CODE16C_TUNE2
	.errnz ($ - T_DOSGETDBCSEV)

	call	FAR PTR DOSGETDBCSEV		; call 16-bit version
	jmp	FAR PTR FLAT:R_DOSGETDBCSEV		; jump back

CODE16C_TUNE2 ENDS


;Create a dummy label to trick MASM into correct fixups

CODE16C_TUNE2 SEGMENT

T_DOSCASEMAP	LABEL FAR

CODE16C_TUNE2 ENDS


CODE32_TUNE2  SEGMENT
	ASSUME CS:FLAT,DS:FLAT,ES:FLAT
DOS32MAPCASE PROC

	push	ebp
	mov	ebp,esp


	cld			;Assume direction flag clear
	xor	eax,eax
	push	eax		; temp storage for return value
	push	esi
	push	edi
	push	eax		; temp storage
	push	eax		;Error flag for cleanup
	push	eax		; temp storage for Stack Allocation Flags
	push	eax		; temp storage for BMP Flags
	push	eax		; temp storage for Alias Flags
	push	eax		; temp storage for ptr param #1
	push	eax		; temp storage for ptr param #2

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

	push	0000			;push for stack comparison later
	mov	eax,ss
	cmp	ax,seg FLAT:DATA32		; standard 32 bit stack?
	jne	short L29		; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

	mov	eax,esp
	cmp	ax,1024
	jae	short L29
	pop	ecx			;old stack comparator
	call	THK32ALLOCSTACK 	; bump the stack down
	push	eax			;old stack comparator on old stack
	mov	esp,eax


;Insure that 1 DWORD exists on stack
	push	eax
L29:


; ****> BEGIN Pointer/Structure Section



	mov	esi,[ebp+12]		; base address

;Pointer  --> datain
	or	esi,esi
	jz	L30

	mov	[ebp-36],esi

;Structures are not Identical
;Structures don't have pointers

; Allocate space on stack
	sub	esp,4			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-36],edi
;Copy structure to new area


;Element country --> country

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32MAPCASE

	mov	WORD PTR [edi],ax

;Element codepage --> codepage

;Adjust registers after conversion
	add	esi,4
	add	edi,2

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32MAPCASE

	mov	WORD PTR [edi],ax

L30:


	mov	esi,[ebp+16]		; base address

;Pointer  --> dataout
	or	esi,esi
	jz	L31

	mov	[ebp-40],esi
	mov	ecx,[ebp+8]		;Get Size Parameter
	or	ecx,ecx
	jz	L31		;Nothing to check

;DWORD --> WORD sized length. Error if Size > 64k
	cmp	ecx,10000h
	jae	INVP_DOS32MAPCASE			;jmp if too long
;ECX holds size in bytes

;Check Boundary Crossing
	mov	eax,esi
	neg	ax
	jz	L31			;0=full 64k of room

	cmp	ax,cx
	jae	L31			;Enough room

	call	Thk32HandleBoundary
	or	eax,eax
	jnz	NOMEM_DOS32MAPCASE			;
	mov	[ebp-40],edi
	or	edx,edx
	js	short L32		;Alloced Mem
	or	BYTE PTR [ebp+(edx*4)-32],2		;Set Flag
	dec	edx
	js	short L33		;Aliases not copied

L32:			;Variable Length Copy

; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK

L33:			;Variable Length No Copy

L31:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

	push	es
	push	ebx			; save ebx
	push	ebp			; save ebp
	mov	eax,esp 		; save current esp
	push	ss
	push	eax


	mov	dx,ss			; get cpl bits to use as dpl bits
	and	dx,3			; mask off rest of register

	or	dl,4			;Force LDT bit on


	;From Name:   Type: unsigned long
	mov	eax,[ebp+8]
	cmp	eax,0ffffh
	ja	INVP_DOS32MAPCASE

	push	ax		;To:unsigned short


	;From Name:   Type: struct COUNTRYCODE
	mov	eax,DWORD PTR [ebp-36]
	or	eax,eax
	jz	short L34			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L34:	push	eax



	;From Name:   Type: char
	mov	eax,DWORD PTR [ebp-40]
	or	eax,eax
	jz	short L35			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L35:	push	eax


;* Convert SS:ESP to 16-bit SS:SP.

	mov	eax,esp 		; use CRMA on ESP
	ror	eax,16
	shl	ax,3
	or	al,dl
	rol	eax,16

	push	eax			; push new stack pointer
	lss	sp,DWORD PTR [esp]	; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

	jmp	FAR PTR T_DOSCASEMAP


INVP_DOS32MAPCASE:
	push	ERROR_INVALIDPARAM
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L36

ERR_DOS32MAPCASE:
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L36

NOMEM_DOS32MAPCASE:
	push	ERROR_NOMEMORY
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L36
R_DOSCASEMAP:				; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

	movzx	esp,sp			; make sure that esp is correct
	lss	esp,[esp]
	pop	ebp
	pop	ebx
	pop	es



;Convert Return Code
;USHORT --> ULONG
	movzx	eax,ax
L36:
;Functions contain pointers, save return code
	mov	[ebp-4],eax		;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> datain


	mov	esi,[ebp-36]		; temp address
	or	esi,esi
	jz	L37



	mov	edi,[ebp+12]		; original address

;Structures are not Identical
;Structures don't have pointers
;Structure doesn't have output semantics
;Return structure to original area

;Deallocate Temporary Structure


;Stack allocated memory deallocated implicitly

L37:		;No action required

;Undo Pointer  --> dataout


	mov	esi,[ebp-40]		; temp address
	or	esi,esi
	jz	L38



	mov	edi,[ebp+16]		; original address
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
	cmp	esi,edi
	je	L38

	test	BYTE PTR[ebp-20],1		;Check for errors A
	jnz	L39			;No copy if error

;Get size for copy out
	mov	ecx,[ebp+8]		;Get Size
;ECX holds size in bytes

;If aliased, then skip over possible copyout
	test	BYTE PTR[ebp-32],2		;Test Alias Flag
	jnz	L40
;Copy out ecx bytes
	push	esi		;Save ptr to temp object

; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK
	pop	esi		;Get ptr to temp object
L40:			;Aliased Label
	push	-32		;Alloc Flag Offset
	mov	edx,2

	call	THK32DEALLOC



L39:			;ErrorLabel A

L38:		;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

	lea	esp,[ebp-44]	; get the old stack
	pop	ecx			;get the new stack
	cmp	ecx,0			;is it new
	jz	@f
	call	THK32FREESTACK		;deallocate the memory
@@:
	lea	esp,[ebp-12]
	pop	edi
	pop	esi
	pop	eax		;Pop saved return code
	leave
	ret				; Remove parameters

DOS32MAPCASE endp

CODE32_TUNE2  ENDS

;* 16-bit code to make API call.

CODE16C_TUNE2 SEGMENT

	ASSUME CS:CODE16C_TUNE2
	.errnz ($ - T_DOSCASEMAP)

	call	FAR PTR DOSCASEMAP		; call 16-bit version
	jmp	FAR PTR FLAT:R_DOSCASEMAP		; jump back

CODE16C_TUNE2 ENDS


;Create a dummy label to trick MASM into correct fixups

CODE16C SEGMENT

T_DOSGETCOLLATE LABEL FAR

CODE16C ENDS


CODE32	SEGMENT
	ASSUME CS:FLAT,DS:FLAT,ES:FLAT
DOS32QUERYCOLLATE PROC

	push	ebp
	mov	ebp,esp


	cld			;Assume direction flag clear
	xor	eax,eax
	push	eax		; temp storage for return value
	push	esi
	push	edi
	push	eax		; temp storage
	push	eax		;Error flag for cleanup
	push	eax		; temp storage for Stack Allocation Flags
	push	eax		; temp storage for BMP Flags
	push	eax		; temp storage for Alias Flags
	push	eax		; temp storage for ptr param #1
	push	eax		; temp storage for ptr param #2
	push	eax		; temp storage for ptr param #3

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

	push	0000			;push for stack comparison later
	mov	eax,ss
	cmp	ax,seg FLAT:DATA32		; standard 32 bit stack?
	jne	short L44		; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

	mov	eax,esp
	cmp	ax,1024
	jae	short L44
	pop	ecx			;old stack comparator
	call	THK32ALLOCSTACK 	; bump the stack down
	push	eax			;old stack comparator on old stack
	mov	esp,eax


;Insure that 1 DWORD exists on stack
	push	eax
L44:


; ****> BEGIN Pointer/Structure Section



	mov	esi,[ebp+12]		; base address

;Pointer  --> datain
	or	esi,esi
	jz	L45

	mov	[ebp-36],esi

;Structures are not Identical
;Structures don't have pointers

; Allocate space on stack
	sub	esp,4			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-36],edi
;Copy structure to new area


;Element country --> country

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOLLATE

	mov	WORD PTR [edi],ax

;Element codepage --> codepage

;Adjust registers after conversion
	add	esi,4
	add	edi,2

;ULONG --> USHORT

	mov	eax,DWORD PTR [esi]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOLLATE

	mov	WORD PTR [edi],ax

L45:


	mov	esi,[ebp+16]		; base address

;Pointer  --> dataout
	or	esi,esi
	jz	L46

	mov	[ebp-40],esi
	mov	ecx,[ebp+8]		;Get Size Parameter
	or	ecx,ecx
	jz	L46		;Nothing to check

;DWORD --> WORD sized length. Error if Size > 64k
	cmp	ecx,10000h
	jae	INVP_DOS32QUERYCOLLATE			;jmp if too long
;ECX holds size in bytes

;Check Boundary Crossing
	mov	eax,esi
	neg	ax
	jz	L46			;0=full 64k of room

	cmp	ax,cx
	jae	L46			;Enough room

	call	Thk32HandleBoundary
	or	eax,eax
	jnz	NOMEM_DOS32QUERYCOLLATE 		;
	mov	[ebp-40],edi
	or	edx,edx
	js	short L47		;Alloced Mem
	or	BYTE PTR [ebp+(edx*4)-32],2		;Set Flag

L47:			;Variable Length Copy

;Item semantics are NOT input

L48:			;Variable Length No Copy

L46:


	mov	esi,[ebp+20]		; base address

;Pointer  --> len
	or	esi,esi
	jz	L49

	mov	[ebp-44],esi

;Have PU/LONG, want PU/SHORT
;Use the LONG as buffer, only if it doesn't
;cross boundary

;Check Boundary Crossing - fixed size item
	cmp	si,65532
	jbe	L49			;Enough room

; Allocate space on stack
	sub	esp,2			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-44],edi

L49:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

	push	es
	push	ebx			; save ebx
	push	ebp			; save ebp
	mov	eax,esp 		; save current esp
	push	ss
	push	eax


	mov	dx,ss			; get cpl bits to use as dpl bits
	and	dx,3			; mask off rest of register

	or	dl,4			;Force LDT bit on


	;From Name:   Type: unsigned long
	mov	eax,[ebp+8]
	cmp	eax,0ffffh
	ja	INVP_DOS32QUERYCOLLATE

	push	ax		;To:unsigned short


	;From Name:   Type: struct COUNTRYCODE
	mov	eax,DWORD PTR [ebp-36]
	or	eax,eax
	jz	short L50			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L50:	push	eax



	;From Name:   Type: char
	mov	eax,DWORD PTR [ebp-40]
	or	eax,eax
	jz	short L51			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L51:	push	eax



	;From Name:   Type: unsigned long
	mov	eax,DWORD PTR [ebp-44]
	or	eax,eax
	jz	short L52			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L52:	push	eax


;* Convert SS:ESP to 16-bit SS:SP.

	mov	eax,esp 		; use CRMA on ESP
	ror	eax,16
	shl	ax,3
	or	al,dl
	rol	eax,16

	push	eax			; push new stack pointer
	lss	sp,DWORD PTR [esp]	; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

	jmp	FAR PTR T_DOSGETCOLLATE


INVP_DOS32QUERYCOLLATE:
	push	ERROR_INVALIDPARAM
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L53

ERR_DOS32QUERYCOLLATE:
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L53

NOMEM_DOS32QUERYCOLLATE:
	push	ERROR_NOMEMORY
	pop	eax
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L53
R_DOSGETCOLLATE:				; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

	movzx	esp,sp			; make sure that esp is correct
	lss	esp,[esp]
	pop	ebp
	pop	ebx
	pop	es



;Convert Return Code
;USHORT --> ULONG
	movzx	eax,ax
L53:
;Functions contain pointers, save return code
	mov	[ebp-4],eax		;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> datain


	mov	esi,[ebp-36]		; temp address
	or	esi,esi
	jz	L54



	mov	edi,[ebp+12]		; original address

;Structures are not Identical
;Structures don't have pointers
;Structure doesn't have output semantics
;Return structure to original area

;Deallocate Temporary Structure


;Stack allocated memory deallocated implicitly

L54:		;No action required

;Undo Pointer  --> dataout


	mov	esi,[ebp-40]		; temp address
	or	esi,esi
	jz	L55



	mov	edi,[ebp+16]		; original address
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
	cmp	esi,edi
	je	L55

	test	BYTE PTR[ebp-20],1		;Check for errors A
	jnz	L56			;No copy if error

;Get size for copy out
	mov	ecx,[ebp+8]		;Get Size
;ECX holds size in bytes

;If aliased, then skip over possible copyout
	test	BYTE PTR[ebp-32],2		;Test Alias Flag
	jnz	L57
;Copy out ecx bytes
	push	esi		;Save ptr to temp object

; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK
	pop	esi		;Get ptr to temp object
L57:			;Aliased Label
	push	-32		;Alloc Flag Offset
	mov	edx,2

	call	THK32DEALLOC



L56:			;ErrorLabel A

L55:		;No action required

;Undo Pointer  --> len


	mov	esi,[ebp-44]		; temp address
	or	esi,esi
	jz	L60



	mov	edi,[ebp+20]		; original address

;This item is either on the stack, or is still
;in its original position.
;Output semantics convert in place

	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

L60:		;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

	lea	esp,[ebp-48]	; get the old stack
	pop	ecx			;get the new stack
	cmp	ecx,0			;is it new
	jz	@f
	call	THK32FREESTACK		;deallocate the memory
@@:
	lea	esp,[ebp-12]
	pop	edi
	pop	esi
	pop	eax		;Pop saved return code
	leave
	ret				; Remove parameters

DOS32QUERYCOLLATE endp

CODE32	ENDS

;* 16-bit code to make API call.

CODE16C SEGMENT

	ASSUME CS:CODE16C
	.errnz ($ - T_DOSGETCOLLATE)

	call	FAR PTR DOSGETCOLLATE		; call 16-bit version
	jmp	FAR PTR FLAT:R_DOSGETCOLLATE		; jump back

CODE16C ENDS



CODE32	SEGMENT

	ASSUME CS:FLAT,DS:FLAT,SS:FLAT

THK32COPYBLOCK:

; Copy ECX bytes from ESI to EDI
	mov	eax,3
	and	eax,ecx
	shr	ecx,2
	rep movsd
	mov	ecx,eax
	rep movsb

	ret

CODE32	ENDS

	END
