home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 8 Other
/
08-Other.zip
/
GIFASM.ZIP
/
DECOMP.ASM
Wrap
Assembly Source File
|
1990-03-27
|
6KB
|
247 lines
; asm routines for decompressing Compuserve GIF lzw data.
; note: you must supply the putbyte routine and the header reading routines
;
; NOTE! THIS CODE HAS NOT BEEN TESTED WITH OS/2. It was written for DOS and
; recently modified to be used with OS/2. I haven't had the time to
; work with or test the OS/2 version.
;
;
; GIF and 'Graphics Interchange Format' are trademarks of Compuserve,
; Inc., an H&R Block Company
;
;
;
;
; MS C 5.1 prototype
;
; SHORT pascal gifdecompress(USHORT codesize, // initial code size
; SHORT (*getbyte)(), // routine to get byte from file
; VOID (*putbyte)(SHORT), // routine to write byte to file
; SEL lzwseg); // selector for decompression table
; return values
;
; 0 Normal completion
; -1 Invalid code size
; caution - no other error codes are returned.
;
;
; lzw decompression table entry
lzwrec STRUC
prev DW ? ; prefix code
char DB ? ; suffix char
lzwrec ENDS
; Declare segments
.MODEL LARGE,PASCAL
.DATA
codesize DW ?
getbyte DD ?
lzwseg DW ?
.CODE
gifdecompress PROC USES si di, cdsz:WORD,get_byte:PTR,putbyte:PTR,lzw_seg:WORD
mov ax,lzw_seg ; Set selector for decompression table
mov lzwseg,ax
les ax,get_byte ; Set pointer for getbyte routine
mov WORD PTR getbyte,ax
mov WORD PTR getbyte+2,es
mov ax,cdsz ; Validate code size
mov codesize,ax
cmp ax,2 ; Code size < 2?
jl cserr ; Yes, error
cmp ax,8 ; Code size <= 8?
jle init ; Yes, it's good
cserr: mov ax,-1 ; Code size error
jmp l1a
init: xor ax,ax ; Initialize variables
mov remaining,ax
mov bits,ax
mov bits+2,ax
mov stack_count,ax
call init_tab ; Initialize table
l1: call read_code ; Get a code
cmp ax,eof ; End of file?
jne l2 ; No
xor ax,ax ; Zero return
l1a:
ret ; Done
l2: cmp ax,clear ; Clear code?
jne l7 ; No
call init_tab ; Initialize table
call read_code ; Read next code
mov cur_code,ax ; Initialize variables
mov old_code,ax
mov k,al
mov fin_char,al
mov al,k
push es ; Preserve seg reg
push ax ; Character to be passed
call putbyte ; Write character
add sp,2 ; Adjust stack
pop es
jmp short l1 ; Get next code
l7: mov cur_code,ax ; Save new code
mov in_code,ax
mov es,lzwseg ; Point to hash table
cmp ax,free_code ; Code in table? (k<w>k<w>k)
jl l11 ; Yes
mov ax,old_code ; Get previous code
mov cur_code,ax ; Make current
mov al,fin_char ; Get old last char
push ax ; Push it
inc stack_count
l11: mov ax,clear ; Code or character?
cmp ax,cur_code
jg l15 ; Char
mov bx,cur_code ; Convert code to address
call index
mov al,es:2[si] ; Get suffix char
push ax ; Push it
inc stack_count
mov ax,es:[si] ; Get prefix code
mov cur_code,ax ; Save it
jmp short l11 ; Translate again
l15: push ds ; Restore seg reg
pop es
mov ax,cur_code ; Get code
mov fin_char,al ; Save as final, k
mov k,al
push ax ; Push it
inc stack_count
mov cx,stack_count ; Pop stack
jcxz l18 ; If anything there
l17: pop ax
push cx ; Save registers
push es
push ax ; Character to be passed
call putbyte ; Write character
add sp,2 ; Adjust stack
pop es ; Restore registers
pop cx
loop l17
l18: mov stack_count,cx ; Clear count on stack
call add_code ; Add new code to table
mov ax,in_code ; Save input code
mov old_code,ax
mov bx,free_code ; Hit table limit?
cmp bx,max_code
jl l23 ; Less means no
cmp nbits,12 ; Still within twelve bits?
je l23 ; No (next code should be clear)
inc nbits ; Increase code size
shl max_code,1 ; Double max code
l23: jmp l1 ; Get next code
gifdecompress ENDP
.DATA
clear DW ?
eof DW ?
cur_code DW ?
old_code DW ?
in_code DW ?
free_code DW ?
stack_count DW ?
nbits DW ?
max_code DW ?
fin_char DB ?
k DB ?
.CODE
read_code PROC NEAR
rd1: mov cx,remaining ; Get bits held
cmp cx,nbits ; Have bits required for code?
jge rd3 ; Yes
push es ; Preserve seg reg
call getbyte ; No, get a byte
pop es
mov cx,remaining ; Get bits held
xor dx,dx
jcxz rd2a ; If zero, don't need to shift
rd2: shl ax,1 ; Shift to into place
rcl dx,1
loop rd2
rd2a: mov bits,dx ; Move new bits in
mov cx,bits+2
or ax,cx
mov bits+2,ax
add remaining,8 ; Increment remainding count
jmp short rd1 ; See if have required bits now
rd3: mov dx,bits ; Get bits remaining
mov ax,bits+2
mov bx,nbits
dec bx
shl bx,1
and ax,masks[bx] ; Mask off unwanted bits
push ax ; Save code
mov ax,bits+2 ; Get low order bits
mov cx,nbits
rd4: shr dx,1 ; Shift rest of bits
rcr ax,1
loop rd4
mov bits,dx ; Save new bits remaining
mov bits+2,ax
mov ax,nbits ; Compute new remaining count
sub remaining,ax
pop ax ; Restore code
ret
read_code ENDP
.DATA
masks DW 0001h,0003h,0007h,000fh
DW 001fh,003fh,007fh,00ffh
DW 01ffh,03ffh,07ffh,0fffh
remaining DW ?
bits DW 2 DUP (?)
.CODE
init_tab PROC NEAR
mov cx,codesize ; Get code size
mov ax,1
shl ax,cl ; Compute clear code
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 cx ; Compute bits per code
mov nbits,cx
mov ax,1 ; Compute maximum code value
shl ax,cl
mov max_code,ax
ret
init_tab ENDP
index PROC NEAR
mov si,bx
shl si,1 ; si = bx * 3 (3 byte hash entries)
add si,bx ; si = bx * 2 + bx
ret
index ENDP
add_code PROC NEAR
mov bx,free_code ; Get new code
call index ; Convert to address
push es ; Preserve seg reg
mov es,lzwseg ; Point to hash table
mov al,k ; Get suffix char
mov es:[si].char,al ; Save it
mov ax,old_code ; Get prefix code
mov es:[si].prev,ax ; Save it
pop es
inc free_code ; Set next code
ret
add_code ENDP
END