Category : Assembly Language Source Code
Archive   : LZ.ZIP
Filename : LZDCMP.ASM
;Tom Pfau
;Digital Equipment Corporation
;Parsippany, NJ
;Constants
clear equ 256
eof equ 257
first_free equ 258
maxmax equ 4096
include macros.mlb
;Hash table entry
hash_rec struc
next dw ? ; prefix code
char db ? ; suffix char
hash_rec ends
;Declare segments
code segment byte public 'code'
code ends
stack segment word stack 'data'
dw 128 dup (?)
stack ends
data segment word public 'data'
data ends
memory segment para public 'memory'
hash label hash_rec
memory ends
;Start coding
code segment
assume cs:code,ds:data,ss:stack,es:data
start proc far
mov bx,seg hash ;End of program
mov ax,ds ;Beginning of program
sub bx,ax ;Size of program
inc bx ;Make sure
setmem bx ;Set program size
mov bx,data ;Address data segment
mov es,bx
mov ds,bx
print input_prompt ;Get file names
input input_file
print crlf
print output_prompt
input output_file
print crlf
mov al,input_file+1 ;Terminate with nulls
xor ah,ah
mov si,ax
mov input_file+2[si],0
mov al,output_file+1
mov si,ax
mov output_file+2[si],0
hopen input_file+2,0 ;Open input and output
mov input_handle,ax
hcreat output_file+2,0
mov output_handle,ax
call decompress ;Decompress files
hclose input_handle
hclose output_handle
exit ;Done
start endp
data segment
input_prompt db 'Input file: $'
output_prompt db 'Output file: $'
input_file db 80,0,80 dup (?)
output_file db 80,0,80 dup (?)
crlf db 13,10,'$'
input_handle dw ?
output_handle dw ?
data ends
decompress proc near
malloc 768 ;Allocate space for hash table
mov hash_seg,ax ;Save segment address
hread input_handle,input_buffer,1024 ;Read from input
l1: call read_code ;Get a code
cmp ax,eof ;End of file?
jne l2 ;no
cmp output_offset,0 ;Data in output buffer?
je l1a ;no
hwrite output_handle,output_buffer,output_offset ;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
mov al,k
call write_char ;Write character
jmp l1 ;Get next code
l7: mov cur_code,ax ;Save new code
mov in_code,ax
mov es,hash_seg ;Point to hash table
cmp ax,free_code ;Code in table? (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: cmp cur_code,255 ;Code or character?
jle l15 ;Char
mov bx,cur_code ;Convert code to address
call index
mov al,es:2[bx] ;Get suffix char
push ax ;push it
inc stack_count
mov ax,es:[bx] ;Get prefix code
mov cur_code,ax ;Save it
jmp 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
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
data segment
hash_seg dw ?
cur_code dw ?
old_code dw ?
in_code dw ?
free_code dw first_free
stack_count dw 0
nbits dw 9
max_code dw 512
fin_char db ?
k db ?
data ends
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?
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 bp,ax ;save byte offset
sub cx,ax ;Calculate bytes left
add ax,offset input_buffer ;Point to char
mov si,ax
lea di,input_buffer ;Point to beginning of buffer
rep movsb ;Move last chars down
hread input_handle,[di],bp ;Fill rest of buffer
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
read_code endp
data segment
masks dw 1ffh,3ffh,7ffh,0fffh
input_buffer db 1024 dup (?)
bit_offset dw 0
data ends
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?
jl wc1 ;no
push ax ;Save registers
push cx
hwrite output_handle,output_buffer,di ;Write buffer to file
pop cx
pop ax
mov di,0 ;Point to beginning of buffer
mov output_offset,di
wc1: lea di,output_buffer[di] ;Point into buffer
stosb ;Store char
inc output_offset ;Increment number of chars in buffer
ret
write_char endp
data segment
output_offset dw 0
output_buffer db 1024 dup (?)
data ends
index proc near
mov bp,bx ;bx = bx * 3 (3 byte entries)
shl bx,1 ;bp = bx
add bx,bp ;bx = bx * 2 + bp
ret
index endp
add_code proc near
mov bx,free_code ;Get new code
call index ;convert to address
push es ;point to hash table
mov es,hash_seg
mov al,k ;get suffix char
mov es:[bx].char,al ;save it
mov ax,old_code ;get prefix code
mov es:[bx].next,ax ;save it
pop es
inc free_code ;set next code
ret
add_code endp
code ends
end start
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/