home *** CD-ROM | disk | FTP | other *** search
- ;//////////////////////////////////////////////////////////////////////////////
- ;/ QuickBASIC & PDS Callable LZSS Decoder /
- ;/ By Rich Geldreich 1992 /
- ;/ /
- ;/ Anyone may freely use and distribute this program as long as proper credit /
- ;/ is given when it is used. Thanks! /
- ;/ /
- ;//////////////////////////////////////////////////////////////////////////////
-
- ;Assembled with Turbo Assembler v2.0
- ;ToDo list: Add critical error handler for those hard to beat "abort, retry,
- ;ignore?" messages
-
- .286 ;<-- sorry, needs at least a 286!
- Ideal
- Model Small
-
- BufferSize = 4096
- DiskBuffer = 12000;24,000 bytes total used for disk buffers! Ouch!
- ;The procedure should be modified so it dynamically allocates
- ;the buffers when it's ran... That's your job!
-
- MaxMatch = 74
- Threshold = 2
-
- DataSeg
-
- Assume ds:@data, es:@data, cs:@code, ss:nothing
-
- Even
-
- R dw 0
- InAddress dw 0
- OutAddress dw 0
-
- InHandle dw 0
- OutHandle dw 0
-
- TempChar db 0
- Bitsleft db 0
-
- RingBuffer db BufferSize dup(?)
-
- InBuffer db DiskBuffer dup(?)
- Outbuffer db DiskBuffer dup(?)
-
- CodesLeft dw ?
- dw ?
-
- CodeSeg
- Public SlDecode
-
- SourceOffset equ [ss:bp+12]
- SourceSegment equ [ss:bp+10]
- DestOffset equ [ss:bp+8]
- DestSegment equ [ss:bp+6]
- ;//////////////////////////////////////////////////////////////////////////////
- ;Main QB callable routine
- Proc SlDecode
- Push bp
- Mov bp, sp
- Push ds es si di
-
- Call Init ;Initialize everything
-
- Call OpenFiles ;Open the files
- Jc @@FError ;Error?
-
- Call Decompress ;Decompress
- Jc @@DError ;Error?
-
- Xor ax, ax ;No error
-
- @@Exit: Call CloseFiles ;Close the open files
- Pop di si es ds bp ;Pop regs and return to caller
- Retf 8
- @@FError:
- Mov ax, -1 ;File error
- Jmp @@Exit
- @@DError:
- Mov ax, -2 ;Decompression error
- Jmp @@Exit
- Endp SlDecode
- ;//////////////////////////////////////////////////////////////////////////////
- ;Opens files.
- Proc OpenFiles
- Mov ax, @data
- Mov es, ax
-
- Mov ds, SourceSegment
- Mov dx, SourceOffset
- Mov ax, 03D00h
- Int 021h
- Jc @@Error
- Mov [es:InHandle], ax
-
- Mov ds, DestSegment
- Mov dx, DestOffset
- Mov ax, 03C00h
- Xor cx, cx
- Int 021h
- Jc @@Error
- Mov [es:OutHandle], ax
- @@Error:
- Ret
- Endp OpenFiles
- ;//////////////////////////////////////////////////////////////////////////////
- ;Closes any open files.
- Proc CloseFiles
- Push ax
- Mov bx, [ds:InHandle]
- Cmp bx, 0ffffh
- Je @@NextFile ;Is this file really open?
- Mov ah, 03Eh
- Int 021h ;Close it then
- @@NextFile:
- Mov bx, [ds:OutHandle]
- Cmp bx, 0ffffh
- Je @@Alldone
- Mov ah, 03Eh
- Int 021h
- @@AllDone:
- Pop ax
- Ret
- Endp CloseFiles
- ;//////////////////////////////////////////////////////////////////////////////
- ;Fills up the input buffer.
- Proc FillBuffer
- Push ax bx cx dx
- Mov ah, 03fh
- Mov bx, [ds:InHandle]
- Mov cx, DiskBuffer
- Mov dx, offset InBuffer
- Int 021h ;CF now has error, if any
- Mov si, offset Inbuffer
- Pop dx cx bx ax
- Ret
- Endp FillBuffer
- ;//////////////////////////////////////////////////////////////////////////////
- ;Flushes the output buffer.
- Proc FlushBuffer
-
- Push ax bx cx dx
-
- Mov di, offset Outbuffer
-
- Mov ah, 040h
- Mov bx, [ds:OutHandle]
- Mov cx, [ds:OutAddress]
- Sub cx, di
- Mov dx, offset OutBuffer
- Int 021h
-
- Jc @@Error ;Error while flushing?
- Cmp ax, cx ;All bytes written?
- Je @@OK
- Stc
- Jmp short @@Error
- @@OK:
- Clc
- @@Error:
- Pop dx cx bx ax
- Ret
- Endp FlushBuffer
-
- ;//////////////////////////////////////////////////////////////////////////////
- ;Gets a multibit code from the input stream- CH has # of bits wanted.
- Even
- Proc GetCode
- Mov si, [ds:InAddress]
- Mov ax, [word ds:TempChar]
- Mov cl, ah
- Xor ah, ah
- Mov di, offset InBuffer+DiskBuffer
- Mov bh, 8
-
- Mov dl, cl ;Work=TempChar >> (8-Bitsleft)
- Neg cl
- Jz @@FillUp ;Get 8 more bits if none
- Add cl, bh
- @@NZ:
- Mov bp, ax
- Shr bp, cl
- Mov cl, dl
-
- Cmp ch, cl ;Enough bits?
- Jna @@20
- @@15:
- Cmp si, di ;End of input buffer?
- Je @@FillBuffer2 ;Fill up if so
- @@BF2:
- Lodsb ;TempChar=Byte
- Mov dx, ax
- Shl dx, cl ;Work=Work or TempChar << BitsLeft
- Or bp, dx
- Add cl, bh
- Cmp ch, cl ;Enough bits?
- Ja @@15 ;Nope, get more
- @@20:
- Sub cl, ch ;Less bits now
- Mov ah, cl ;Save TempChar and BitsLeft
- Mov [word ds:TempChar], ax
- Mov [ds:InAddress], si ;Save in address
- Clc ;No errors
- Ret
-
- Even
- @@FillUp:
- Cmp si, di
- Je @@FillBuffer1
- @@BF1:
- Lodsb
-
- Mov dl, bh ;8 more bits now
- Jmp @@NZ ;CL=0 DL=8 now
-
- @@FillBuffer1:
- Call FillBuffer
- Jnc @@BF1
- Ret
-
- @@FillBuffer2:
- Call FillBuffer
- Jnc @@BF2
- Ret
- Endp GetCode
-
- ;//////////////////////////////////////////////////////////////////////////////
- ;Initializes the ring buffer to space characters, sets the read & write
- ;pointers to their starting states, etc.
- Proc Init
- Mov ax, @data
- Mov es, ax
- Mov ds, ax
-
- Mov di, offset RingBuffer
- Mov cx, BufferSize-MaxMatch
- Mov al, 32
- Rep Stosb ;Clears ring buffer with space characters
-
- ;Make sure the input buffer gets filled up on next read
- Mov [ds:InAddress], offset InBuffer+DiskBuffer
-
- ;Next byte outputted goes to the start of the output buffer
- Mov [ds:OutAddress], offset OutBuffer
-
- ;R=BufferSize-MaxMatch
- Mov [ds:R], (BufferSize-MaxMatch)+Offset RingBuffer
-
- Mov ax, 0ffffh
- Mov [ds:InHandle], ax
- Mov [ds:OutHandle], ax
- Mov [ds:BitsLeft], 0
-
- Ret
- Endp Init
- ;//////////////////////////////////////////////////////////////////////////////
- ;Actuall decompression subroutine.
- Proc Decompress
- Mov ax, @Data
- Mov ds, ax
- Mov es, ax
-
- ;Retrieve # of codes to process and check to see
- ;if the source file has the correct header("RG")
- Mov bx, [ds:InHandle]
- Mov dx, offset CodesLeft-2
- Mov cx, 6
- Mov ah, 03Fh
- Int 021h
- Jc @@Error
- Cmp [word ds:CodesLeft-2], 'R'+'G'*256
- Jne @@Error
-
- Jmp @@MainLoop ;Start decompressing
-
- @@Error:
- Stc
- Ret
-
- @@CheckHigh:
- Sub [ds:CodesLeft+2], 1
- Jnc @@Continue
- Call FlushBuffer ;Save what's in the disk buffer
- Ret ;CF has error, if any
-
- @@FlushBuffer:
- Mov [ds:OutAddress], di
- Call FlushBuffer
- Jc @@Error
- Jmp @@Flushed
-
- @@WrapBack:
- Mov di, offset RingBuffer
- Jmp @@Wraped
-
- Even
- @@MainLoop:
- Sub [ds:Codesleft], 1 ;Sets carry if decrement goes to 0ffffh
- Jc @@CheckHigh
- @@Continue:
- Mov ch, 9 ;Get 9 bits of code
- Call GetCode
- Jc @@Error ;Exit if error
- Shr bp, 1 ;Put flag bit in carry
- Jc @@Match ;Is it a character or position/length pair?
-
- Mov ax, bp ;It's a character...
- Mov di, [ds:OutAddress]
- Stosb ;Put the character in the disk buffer
- Cmp di, offset OutBuffer+DiskBuffer
- Je @@Flushbuffer ;Flush if full
- @@Flushed:
- Mov [ds:OutAddress], di
- Mov di, [ds:R]
- Stosb ;Put the character in the ring buffer
- Cmp di, offset RingBuffer+BufferSize
- Je @@WrapBack ;Increment position MOD buffersize
- @@Wraped:
- Mov [ds:R], di
- Jmp @@MainLoop ;Do it again
-
- @@Error2:
- Ret
- Even
- @@LongMatch:
- Mov ch, 11
- Call GetCode
- Jc @@Error2
- Mov si, bp
-
- Shl bl, 1
- Shl bl, 1
- Rcl si, 1
- Shr bl, 1
- Shr bl, 1
-
- Mov cx, bx
- And cx, 63
- Add cl, 11
- Jmp @@LMReady
- Even
- @@Match:
- Shr bp, 1
- Mov bx, bp
- Jc @@LongMatch
- Mov ch, 8 ;(7+8)=(12+3)
- Call GetCode
- Jc @@Error2 ;Exit if error
- Mov cx, bp
- Shl cx, 7
- And bl, 127
- Or cl, bl
- Mov si, cx ;SI = buffer address
- Shr si, 3 ;Skip the match length
- And cx, 7
- Add cl, Threshold+1
- @@LMReady:
-
- And si, 4095
- Add si, offset RingBuffer
-
- Mov di, [ds:OutAddress]
- Mov bx, [ds:R]
-
- Mov ax, ((offset RingBuffer)+BufferSize-(MaxMatch+1))
-
- ;Can a fast copy safely be used?
- ;(is there any danger of a pointer wrapping back, if so then
- ;do a slow copy)
-
- Cmp si, ax
- Jnb @@SlowCopyInit
-
- Cmp bx, ax
- Jnb @@SlowCopyInit
-
- Cmp di, ((offset OutBuffer)+DiskBuffer-(MaxMatch+1))
- Jnb @@SlowCopyInit
-
- ;CX/2 for in-line coding
- Shr cx, 1
- Jnc @@FastCopy ;Not odd number of bytes to copy?
- Lodsb ;Copy one byte
- Stosb
- Mov [ds:bx], al
- Inc bx
- Even
- @@FastCopy:
- Rept 2 ;Copy two bytes- a word move cannot
- Lodsb ;be used, unless a special case is taken care
- Stosb ;of; but a byte at a time should do
- Mov [ds:bx], al
- Inc bx
- Endm
- Loop @@FastCopy
-
- Mov [ds:R], bx ;Save pointers and get next code
- Mov [ds:OutAddress], di
- Jmp @@MainLoop
-
- ;The following does a slow copy, the pointers are checked as they are
- ;modified to see if they need wrapping back.
-
- @@SlowCopyInit:
- Mov dx, offset RingBuffer+BufferSize
- Mov bp, offset OutBuffer+DiskBuffer
- Even
- @@SlowCopy:
- Lodsb
- Stosb
- Mov [ds:bx], al
- Inc bx
- Cmp si, dx
- Je @@WrapBack2
- @@WB2:
- Cmp bx, dx
- Je @@WrapBack3
- @@WB3:
- Cmp di, bp
- Je @@FlushBuffer2
- @@FB2:
- Loop @@SlowCopy
- Mov [ds:R], bx
- Mov [ds:OutAddress], di
- Jmp @@MainLoop
-
-
- @@WrapBack2:
- Mov si, offset RingBuffer
- Jmp @@WB2
-
- @@WrapBack3:
- Mov bx, offset RingBuffer
- Jmp @@WB3
-
- @@FlushBuffer2:
- Mov [ds:OutAddress], di
- Call FlushBuffer
- Jnc @@FB2
- Ret
- Endp Decompress
- ;///////////////////////////End of SLDECODE.ASM/////////////////////////////////
- End
-