Source file: /~heha/j/japextra.zip/GIFDECO.ASM

; asm routine for decompressing Compuserve GIF lzw data.
	ideal
	model	small,pascal
	P386
public GifDeco
extrn GlobalAlloc: far
extrn GlobalFree: far

;wie groß ist lzw_table? 12KB?
struc TLzwRec
 prev	DW	 ?			; prefix code
 char	DB	 ?			; suffix char
ends TLzwRec

macro CALCINDEX dest,src
	mov	dest,src
	shl	dest,1			; si = bx * 3 (3 byte hash entries)
	add	dest,src		; si = bx * 2 + bx
endm

CODESEG

proc GifDeco
;Bug in TASM erfordert umgekehrte ARG-Reihenfolge
arg DesiredBits: Byte
arg xbytes: Word
arg ImageWidth:Word
arg BitmapData: Word	;Speicher muß gelöscht sein, oder es wird geODERt!
arg LzwData: far ptr byte
local ClearCode: Word
local x: Word				;X-Pixelkoordinate
local CodeSize: Byte:1
local Count: Byte:1			;Zähler für Bytes im InputStrom
local RemainingW: Word			;aufeinanderfolgend mit nBits!
Remaining equ byte low RemainingW
nbits equ byte high RemainingW		;momentane GIF-Arbeitsbitbreite
local clear: Word			;Clear-Code
local eof: Word
local free_code: Word
local max_code: Word
local PutByte: Word
local Old_Code: Word
local K: Byte:1
local fin_char: Byte:1
local in_code: Word
;ES:DI	Zeiger auf LzwRec-Tabelle, High-Teil von EDI ist definitiv Null
;FS:ESI	Zeiger auf Input-LZW-Daten
;GS:EBX	Zeiger auf Ausgabe-Daten
;EDX	(restliche) Bits vom Eingabestrom
;SS:BP	Stapelrahmenzeiger
;CX	Stack-Zähler

	call	GlobalAlloc,0,0 12*1024 ;12K via ES erreichbar
	or	ax,ax
	jz	@@e			;kein Speicher - raus mit FALSE!
	mov	es,ax
	mov	al,[DesiredBits]
	mov	dx,offset PutNibble386
	cmp	al,4
	je	@@setput
	mov	dx,offset PutByte386
	cmp	al,8
	je	@@setput
	mov	dx,offset PutBit386
@@setput:
	mov	[PutByte],dx
	xor	esi,esi
	xor	ebx,ebx
	xor	edi,edi			;High-Teil muß Null sein!
	lfs	si,[LzwData]		;fs:esi=Quelle
	mov	gs,[BitmapData]		;gs:ebx=Ziel
	lods	[byte fs:esi]
	cmp	al,2			;muß zwischen 2 und 8 sein!
	jb	@@err
	cmp	al,8
	ja	@@err
	mov	[codesize],al
	xor	eax,eax			; Initialize variables
	mov	[x],ax
	mov	[Count],al
	mov	[remaining],al
	mov	edx,eax			;Bits nullsetzen
	mov	cx,ax			;StackCount
	call	init_tab

@@l1:	call	read_code		; Get a code
	cmp	ax,[eof]		; End of file?
	je	@@ok
	cmp	ax,[clear]		; Clear code?
	jne	@@l7			; No
	call	init_tab		; Initialize table
	call	read_code		; Read next code
	mov	[old_code],ax
	mov	[k],al
	mov	[fin_char],al
	call	[PutByte]		; Write character
	jmp	@@l1			; Get next code
@@l7:
	mov	[in_code],ax
	cmp	ax,[free_code]		; Code in table? (k<w>k<w>k)
	jl	@@l11			; Yes
	mov	al,[fin_char]		; Get old last char
	push	ax			; Push it
	 inc	cx
	 mov	ax,[old_code]		; Get previous code
@@l11:
	cmp	ax,[clear]
	jc	@@l15			; Char
	CALCINDEX di,ax			;AX->DI
	mov	al,[es:di+2]		; Get suffix char
	push	ax			; Push it
	 inc	cx
	 mov	ax,[es:di]		; Get prefix code
	 jmp	@@l11			; Translate again
@@l15:
	mov	[fin_char],al		; Save as final, k
	mov	[k],al
	push	ax			; Push it
	 inc	cx
@@l17:	pop	ax
	call	[PutByte]		; Write character
	loop	@@l17

	mov	ax,[free_code]		; Get new code
	CALCINDEX di,ax			; Convert to address
	mov	ax,[old_code]		; Get prefix code
	stosw				; Save it
	mov	al,[k]			; Get suffix char
	stosb				; Save it
	inc	[free_code]		; Set next code
	mov	ax,[in_code]		; Save input code
	mov	[old_code],ax
	mov	ax,[free_code]		; Hit table limit?
	cmp	ax,[max_code]
	jl	@@l1			; Less means no
	cmp	[nbits],12		; Still within twelve bits?
	je	@@l1			; No (next code should be clear)
	inc	[nbits]			; Increase code size
	shl	[max_code],1		; Double max code
	jmp	@@l1			; Get next code
@@err:	stc
@@ok:	setnc	al
	push	ax
	 call	GlobalFree,es
	pop	ax
@@e:	ret
endp

;(verschachtelte) Prozeduren mit gemeinsamem Stack-Rahmen
proc PutBit386
;Ausgabe Pixel in Speicher ES:EBX; VR: EAX
	or	al,al
	jz	@@e
	mov	ax,[x]
	xor	al,7			;Bit-Reihenfolge im Byte tauschen
	bts	[gs:ebx],ax		;Bit Nummer AX setzen
AdvanceX:
@@e:	mov	ax,[x]
	inc	ax
	cmp	ax,[ImageWidth]
	jc	@@inside
	movzx	eax,[xbytes]
	add	ebx,eax
	xor	ax,ax
@@inside:
	mov	[x],ax
	ret
endp

proc PutNibble386
;Ausgabe Pixel in Speicher ES:EBX; VR: EAX,EDI
	mov	di,[x]
	shr	di,1
	jc	PutByteX
	shl	al,4
PutByteX:
	or	[gs:ebx+edi],al		;Nibble oder Byte setzen
	jmp	AdvanceX
endp

proc PutByte386
;Ausgabe Pixel in Speicher ES:EBX; VR: EAX,EDI
	mov	di,[x]
	jmp	PutByteX
endp

proc init_tab
	push	cx
	 mov	cl,[codesize]		; Get code size
	 mov	ax,1
	 shl	ax,cl
	 mov	[clear],ax
	 inc	ax			; Compute end of info code
	 mov	[eof],ax
	 inc	ax			; Compute first free entry in
	 mov	[free_code],ax		; Code table
	 inc	cl			; Compute bits per code
	 mov	[nbits],cl
	 sub	al,2			;frech - dasselbe wie SUB AX,2
	 add	ax,ax
	 mov	[max_code],ax
	pop	cx
	ret
endp init_tab

proc read_code
;liefert [nBits] Bits in AX aus dem Stream
;unter heftiger Beteiligung von 80386-Befehlen
;VR: EAX,EDX
	push	cx
	 mov	cx,[remainingW]		; Get bits held and nBits
@@1:	 cmp	cl,ch			; Have bits required for code?
	 jnc	@@3			; Yes
	 call	getbyte	                ; No, get a byte ==> EAX
	 shl	eax,cl			;links schieben
	 or	edx,eax			;die alten Bits dazu:
	 add	cl,8			;So einfach ist's mit 32bit!
	 jmp	@@1			; See if have required bits now
@@3:
	 sub	cl,ch
	 mov	[remaining],cl
	 xchg	cl,ch
	 mov	ax,1
	 shl	ax,cl
	 dec	ax
	 and	ax,dx
	 shr	edx,cl			;verbleibende Bits runtersetzen
	pop	cx
	ret
endp

proc getbyte
;lädt Byte nach EAX und übergeht dabei ggf. Stringlängenzähler
	mov	al,[count]
@@2:	or	al,al
	jnz	@@1
	lods	[byte fs:esi]	;Längenzähler laden
	jmp	@@2
@@1:	dec	al
	mov	[count],al
	xor	eax,eax
	lods	[byte fs:esi]	;Datenbyte laden
	ret
endp

	END
Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded