home *** CD-ROM | disk | FTP | other *** search
- 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