Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

;       Copyright (c) 2003-2004 Arjan Bakker
;      
;       Permission is hereby granted, free of charge, to any person obtaining a copy of
;       this software and associated documentation files (the "Software"), to deal in
;       the Software without restriction, including without limitation the rights to
;       use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
;       the Software, and to permit persons to whom the Software is furnished to do so,
;       subject to the following conditions:
;      
;       The above copyright notice and this permission notice shall be included in all
;       copies or substantial portions of the Software.
;      
;       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;       IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
;       FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
;       COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
;       IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
;       CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

                MODULE  bitbuster

; File: bitbuster
;
;       The bitbuster module gives you depack support for data packed
;       using the bitbuster algorithm.
;
; FUNCTION NAMES:
;       The functions <depack> and <depack_raw> are MODULE local, which means you
;       have to add the prefix "bitbuster." to its name. This is to prevent possible
;       name clashes with functions from other libraries you might be using.
;       However, if you define <MAKE_BITBUSTER_GLOBAL> then these functions will be
;       available without the "bitbuster." prefix as well.
;
; COPYRIGHT & CREDITS:
;       This module has been released by Arjan Bakker under the MIT License;
;       please see the top of the source file(s) for the full copyright statement.
       
; DEFINE:       MAKE_BITBUSTER_GLOBAL
;       Defining this will make all public functions that are normally only
;       available with the "bitbuster." prefix to also be available without
;       this prefix. See the introduction of <bitbuster> for more information.
 
; DEFINE:       BITBUSTER_OPTIMIZE_SPEED
;       Defining this will optimize the bitbuster depacker for speed, at the cost of
;       bigger code.


                IFDEF   BITBUSTER_OPTIMIZE_SPEED
; use macro's for getbit routines when optimizing bitbuster depacker for speed
; (inlined code, no overhead by calls)
               
                ; macro to get a bit from the bitstream
                ; carry if bit is set, nocarry if bit is clear
                ; must be entered with second registerset switched in!
                MACRO   GET_BIT_FROM_BITSTREAM
                add     a,a             ; shift out new bit
                jp      nz,.done        ; if remaining value isn't zere, we're done

                ld      a,(hl)          ; get 8 bits from bitstream
                inc     hl              ; increase source data address

                rla                     ; (bit 0 will be set!!!!)
.done:          
                ENDM

                ENDIF                   ; IFDEF BITBUSTER_OPTIMIZE_SPEED
       
       
                IFNDEF  BITBUSTER_OPTIMIZE_SPEED
; use calls for getbit code when not optimizing for speed

                ; macro to get a bit from the bitstream
                ; carry if bit is set, nocarry if bit is clear
                ; must be entered with second registerset switched in!
                MACRO   GET_BIT_FROM_BITSTREAM
                call    get_bit_from_bitstream
                ENDM

                ENDIF                   ; IFNDEF BITBUSTER_OPTIMIZE_SPEED  
       
                       
; FUNCTION:     depack
;       Depack a blob of data that was packed with Bitbuster.
;
; ENTRY:
;       HL - Address of packed data
;       DE - Address to depack to
;
; EXIT:
;       HL - Size of depacked data
;       A  - Number of blocks left to decompress
;       FZ - Last block has been decompressed
;       FNZ- Last block hasn't been decompressed
;
; MODIFIES:
;       #AF, BC, BC', DE, DE', HL, HL'#
;
depack:         ;EXPORT bitbuster.depack
                ;IFDEF  MAKE_BITBUSTER_GLOBAL
@depack:        ;EXPORT depack         
                ;ENDIF
               
                ld      a,(block_count)
                or      a
                jr      nz,depack_continue      ; continue depacking a block if more blocks left
               
                ld      a,(hl)
                ld      (block_count),a         ; store block count
               
                inc     hl                      ; move to size of first block
                ld      (block_start),hl        ; store starting address of block
               
depack_continue:
                ld      hl,(block_start)        ; load starting address of block
                inc     hl
                inc     hl                      ; move over block size
               
                push    de
                call    depack_raw     
               
                ld      (block_start),hl        ; store starting address of next chunk 
                pop     hl
                ex      de,hl
                OR      A,A
                SBC     HL,DE
               
                ld      a,(block_count)
                dec     a
                ld      (block_count),a         ; decrease number of blocks to decompress
                ret
               
; FUNCTION:     depack_raw
;       Depack data that was packed with Bitbuster.
;       Decompresses the RAW data, i.e. the data that is storead after the block
;       count and block size!
;
; ENTRY:
;       HL - Address of packed data
;       DE - Address to depack to
;
; EXIT:
;       HL - Address of first byte after compressed data
;       DE - Address of first byte after decompressed data
;
; MODIFIES:
;       #AF, BC, BC', DE, DE', HL, HL'#
;
depack_raw:     ;EXPORT bitbuster.depack_raw
                ;IFDEF  MAKE_BITBUSTER_GLOBAL
@depack_raw:    ;EXPORT depack_raw             
                ;ENDIF
               
                ld      a,128

depack_loop:    GET_BIT_FROM_BITSTREAM          ; get compression type bit
                jp      c,output_compressed     ; if set, we got lz77 compression
                ldi                             ; copy byte from compressed data to destination (literal byte)
       
                IFDEF   BITBUSTER_OPTIMIZE_SPEED
                GET_BIT_FROM_BITSTREAM          ; get compression type bit
                jp      c,output_compressed     ; if set, we got lz77 compression
                ldi                             ; copy byte from compressed data to destination (literal byte)
                GET_BIT_FROM_BITSTREAM          ; get compression type bit
                jp      c,output_compressed     ; if set, we got lz77 compression
                ldi                             ; copy byte from compressed data to destination (literal byte)
                ENDIF

                jp      depack_loop
       

;handle compressed data
output_compressed:
; calculate length value
                ld      bc,1
get_gamma_value:
                GET_BIT_FROM_BITSTREAM          ; get more bits
                jr      nc,get_gamma_value_end
                GET_BIT_FROM_BITSTREAM          ; get next bit of value from bitstream
                rl      c
                rl      b
                jp      nc,get_gamma_value      ; repeat unless overflow occurred (=end of block marker)
                ret
       
get_gamma_value_end:
                inc     bc                      ; length was stored as length-2 so correct this

                ld      (source_length),bc

                ld      c,(hl)                  ; get lowest 7 bits of offset, plus offset extension bit
                inc     hl                      ; to next byte in compressed data
               
                ld      b,0
                bit     7,c
                jr      z,output_match1         ; no need to get extra bits if carry not set
       
                GET_BIT_FROM_BITSTREAM          ; get offset bit 10
                rl      b
                GET_BIT_FROM_BITSTREAM          ; get offset bit 9
                rl      b
                GET_BIT_FROM_BITSTREAM          ; get offset bit 8
                rl      b
                GET_BIT_FROM_BITSTREAM          ; get offset bit 7
       
                jp      c,output_match2         ; since extension mark already makes bit 7 set
                res     7,c                     ; only clear it if the bit should be cleared
output_match1:  scf
output_match2:  push    hl                      ; address compressed data on stack

                ld      h,d
                ld      l,e                     ; destination address in HL...
                sbc     hl,bc                   ; calculate source address
                       
                ld      bc,(source_length)
       
                ldir                            ; transfer data
       
                pop     hl                      ; address compressed data back from stack
               
                IFDEF   BITBUSTER_OPTIMIZE_SPEED
                GET_BIT_FROM_BITSTREAM          ; get compression type bit
                jp      c,output_compressed     ; if set, we got lz77 compression
                ldi                             ; copy byte from compressed data to destination (literal byte)
                GET_BIT_FROM_BITSTREAM          ; get compression type bit
                jp      c,output_compressed     ; if set, we got lz77 compression
                ldi                             ; copy byte from compressed data to destination (literal byte)
                ENDIF
       
                jp      depack_loop
       
       
                IFNDEF  BITBUSTER_OPTIMIZE_SPEED

; get a bit from the bitstream
; carry if bit is set, nocarry if bit is clear
; must be entered with regular registerset switched in!
get_bit_from_bitstream:
                add     a,a             ; shift out new bit
                ret     nz              ; if remaining value isn't zere, we're done
                                         
                ld      a,(hl)          ; get 8 bits from bitstream
                inc     hl              ; increase source data address
       
                rla                     ;(bit 0 will be set!!!!)
                ret
                ENDIF                   ; IFNDEF BITBUSTER_OPTIMIZE_SPEED
               
source_length:  dw      0               ; length of source string
block_count:    db      0               ; number of blocks to decompress
block_start:    dw      0               ; starting address of next block
       
       
                ENDMODULE