; 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
|
|