home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
compress
/
lz13.arc
/
LZDCMP3.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-10-20
|
7KB
|
277 lines
title lzdcmp - file decompressor using limpel-ziev algorithm
;Tom Pfau
;Digital Equipment Corporation
;Parsippany, NJ
;
;v1.2 - Toad Hall Tweak
; - converting to .COM file
; - uses tweaked MACROS2.MLB
; - Takes input file from command line, outputs to StdOut
; - Added some file error halts (sorry, no msgs yet)
; - Bumped i/o buffers to 4Kb from original 1Kb
;Constants
CLEAR equ 256
EOF equ 257
FIRST_FREE equ 258
BUFFSIZE equ 4096 ;TH
include macros2.mlb
;Hash table entry
hash_rec struc
next dw ? ; prefix code
char db ? ; suffix char
hash_rec ends
;Start coding
code segment para public 'code'
assume CS:code,DS:code, ES:code ;TH
org 100H ;TH
LzDcmp2 proc near
jmp Start ;TH
input_handle dw 0 ;TH default to StdIn
cur_code dw 0 ;?
old_code dw 0 ;?
in_code dw 0 ;?
free_code dw FIRST_FREE
stack_count dw 0
nbits dw 9
max_code dw 512
fin_char db 0 ;?
k db 0 ;?
masks dw 1ffh,3ffh,7ffh,0fffh
bit_offset dw 0
output_offset dw 0
LzDcmp2 endp
start proc near
mov si,80H ;point to PSP cmd line
lodsb ;snarf cmd line len byte
or al,al ;anything on cmd line?
jz Start_Process ;nope, use < stdin
xor ah,ah ;clear msb
;SI now points to 81H
mov dx,si ;not quite first char
inc dx ;DX points to target filename
add si,ax ;point to beyond last char
mov [si],ah ;make file name AsciiZ
mov ax,3D00H ;open file/device
int 21H
jb Terminate ;failed somehow, die
mov input_handle,ax ;save input handle
Start_Process:
call decompress ;Decompress files
Terminate: ;TH errorlevel in AL
;TH Note: I don't bother closing any files .. the 4CH terminate
;seems to let DOS do it nicely. Never had any problems yet
;with running out of handles, etc.
mov ah,4CH ;TH terminate process
int 21H
start endp
decompress proc near
hread input_handle,input_buffer,BUFFSIZE ;TH Read from input
jb Terminate ;TH failed somehow
l1: call read_code ;Get a code
cmp ax,EOF ;End of file?
jne l2 ;no
mov ax,output_offset ;TH output buffer offset
or ax,ax ;TH Data in output buffer?
je l1a ;no (TH return Errorlevel 0)
mov dx,offset output_buffer ;TH buffer to write from
mov cx,ax ;TH nr bytes to write
mov bx,1 ;TH StdOut
mov ah,40H ;TH write to file/dev
int 21H ;flush buffer
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
call write_char ;Write character
jmp l1 ;Get next code
l7: mov cur_code,ax ;Save new code
mov in_code,ax
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
mov ax,cur_code ;TH sigh ...
l11:
;TH AX should have cur_code in any case
; cmp cur_code,255 ;Code or character?
cmp ax,255 ;TH Code or character?
jle l15 ;Char
; mov bx,cur_code ;Convert code to address
mov bx,ax ;TH Convert code to address
call index
mov al,2[bx] ;Get suffix char
push ax ;push it
inc stack_count
mov ax,[bx] ;Get prefix code
mov cur_code,ax ;Save it
jmp l11 ;Translate again
l15:
;TH ax should still have cur_code
; 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
call write_char
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
decompress endp
read_code proc near
mov ax,bit_offset ;Get bit offset
add ax,nbits ;Adjust by code size
xchg bit_offset,ax ;Swap
mov cx,8 ;Calculate byte offset
xor dx,dx
div cx
; cmp ax,1021 ;Approaching end of buffer?
cmp ax,BUFFSIZE-3 ;TH approaching end of buffer?
jl rd0 ;no
push dx ;Save offset in byte
add dx,nbits ;Calculate new bit offset
mov bit_offset,dx
; mov cx,1024 ;1k buffer
mov cx,BUFFSIZE ;TH 4Kb buffer
mov bp,ax ;save byte offset
sub cx,ax ;Calculate bytes left
mov di,offset input_buffer ;TH Point to beginning of buffer
add ax,di ;TH Point to char
mov si,ax
rep movsb ;Move last chars down
;TH I broke the macro!
; hread input_handle,[di],bp ;Fill rest of buffer
mov dx,di ;TH DI points to next empty space
mov cx,bp ;TH bytes to write
mov bx,input_handle ;TH read handle
mov ah,3FH ;TH read from file/device
int 21H
jb File_Error ;TH file error
xor ax,ax ;Clear ax
pop dx ;Restore offset in byte
rd0: add ax,offset input_buffer ;Point to char
mov si,ax
lodsw ;Get word
mov bx,ax ;Save in AX
lodsb ;Next byte
mov cx,dx ;Offset in byte
jcxz rd2 ;If zero, skip shifts
rd1: shr al,1 ;Put code in low (code size) bits of BX
rcr bx,1
loop rd1
rd2: mov ax,bx ;put code in ax
mov bx,nbits ;mask off unwanted bits
sub bx,9
shl bx,1
and ax,masks[bx]
ret
File_Error: ;TH jmp here with errorcode in AL
jmp Terminate ;TH Die
read_code endp
init_tab proc near
mov nbits,9 ;Initialize variables
mov max_code,512
mov free_code,FIRST_FREE
ret
init_tab endp
write_char proc near
mov di,output_offset ;Get offset in buffer
; cmp di,1024 ;Full?
cmp di,BUFFSIZE ;TH Full?
jl wc1 ;no
push ax ;Save registers
push cx
mov dx,offset output_buffer ;TH buffer to write
mov cx,di ;TH nr bytes to write
mov bx,1 ;TH StdOut
mov ah,40H ;TH write to file/dev
int 21H ;write buffer to file
jb File_Error ;TH failed somehow
pop cx
pop ax
xor di,di ;TH ;Point to beginning of buffer
mov output_offset,di
wc1:
; lea di,output_buffer[di] ;Point into buffer
add di,offset output_buffer ;TH
stosb ;Store char
inc output_offset ;Increment number of chars in buffer
ret
write_char endp
index proc near
mov bp,bx ;bx = bx * 3 (3 byte entries)
shl bx,1 ;bp = bx
add bx,bp ;bx = bx * 2 + bp
add bx,offset hash ;TH add in hashtable base offset
ret
index endp
add_code proc near
mov bx,free_code ;Get new code
call index ;convert to address
mov al,k ;get suffix char
mov [bx].char,al ;save it
mov ax,old_code ;get prefix code
mov [bx].next,ax ;save it
inc free_code ;set next code
ret
add_code endp
input_buffer equ $ ;db 1024 dup (?)
output_buffer equ input_buffer+BUFFSIZE ;db 1024 dup (?)
hash equ output_buffer+BUFFSIZE
code ends
end LzDcmp2