; this one is from passport

; This source code is altered and is not the original version found on
; the Exomizer homepage.
; It contains modifications made by qkumba to depack a packed file
; optionally crunched forward, and additional modifications by 4am
; for an optional progress UI.
;
; Original copyright statement follows:
;
; Copyright (c) 2002 - 2018 Magnus Lind.
;
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from
; the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
;   1. The origin of this software must not be misrepresented; you must not
;   claim that you wrote the original software. If you use this software in a
;   product, an acknowledgment in the product documentation would be
;   appreciated but is not required.
;
;   2. Altered source versions must be plainly marked as such, and must not
;   be misrepresented as being the original software.
;
;   3. This notice may not be removed or altered from any distribution.
;
;   4. The names of this software and/or it's copyright holders may not be
;   used to endorse or promote products derived from this software without
;   specific prior written permission.
;
; -------------------------------------------------------------------
; The decruncher jsr:s to the get_crunched_byte address when it wants to
; read a crunched byte into A. This subroutine has to preserve X and Y
; register and must not modify the state of the carry nor the overflow flag.
; -------------------------------------------------------------------
;.import get_crunched_byte
; -------------------------------------------------------------------
; this function is the heart of the decruncher.
; It initializes the decruncher zeropage locations and precalculates the
; decrunch tables and decrunches the data
; This function will not change the interrupt status bit and it will not
; modify the memory configuration.
; -------------------------------------------------------------------
;.export decrunch

; -------------------------------------------------------------------
; Controls if the shared get_bits routines should be inlined or not.
;INLINE_GET_BITS=1
; -------------------------------------------------------------------
; if literal sequences is not used (the data was crunched with the -c
; flag) then the following line can be uncommented for shorter and.
; slightly faster code.
;LITERAL_SEQUENCES_NOT_USED = 1
; -------------------------------------------------------------------
; if the sequence length is limited to 256 (the data was crunched with
; the -M256 flag) then the following line can be uncommented for
; shorter and slightly faster code.
;MAX_SEQUENCE_LENGTH_256 = 1
; -------------------------------------------------------------------
; if the sequence length 3 has its own offset table then the following
; line can be uncommented for in some situations slightly better
; compression at the cost of a larger decrunch table.
EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 1
; -------------------------------------------------------------------
; optional progress UI
.ifndef SHOW_PROGRESS_DURING_DECRUNCH
        SHOW_PROGRESS_DURING_DECRUNCH = 0
.endif
; -------------------------------------------------------------------
; zero page addresses used
; -------------------------------------------------------------------
zp_len_lo = $a7
zp_len_hi = $a8

zp_src_lo  = $ae
zp_src_hi  = zp_src_lo + 1

zp_bits_hi = $fc

zp_bitbuf  = $fd
zp_dest_lo = zp_bitbuf + 1      ; dest addr lo
zp_dest_hi = zp_bitbuf + 2      ; dest addr hi

.ifdef EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
encoded_entries = 68
.else
encoded_entries = 52
.endif

tabl_bi = decrunch_table
tabl_lo = decrunch_table + encoded_entries
tabl_hi = decrunch_table + encoded_entries * 2

        ;; refill bits is always inlined
.macro mac_refill_bits
        pha
        jsr get_crunched_byte
        rol
        sta zp_bitbuf
        pla
.endmacro

.ifdef INLINE_GET_BITS
.macro mac_get_bits
        adc #$80                ; needs c=0, affects v
        asl
        bpl gb_skip
gb_next:
        asl zp_bitbuf
        bne gb_ok
        mac_refill_bits
gb_ok:
        rol
        bmi gb_next
gb_skip:
        bvc skip
gb_get_hi:
        sec
        sta zp_bits_hi
        jsr get_crunched_byte
skip:
.endmacro
.else
.macro mac_get_bits
        jsr get_bits
.endmacro
get_bits:
        adc #$80                ; needs c=0, affects v
        asl
        bpl gb_skip
gb_next:
        asl zp_bitbuf
        bne gb_ok
        mac_refill_bits
gb_ok:
        rol
        bmi gb_next
gb_skip:
        bvs gb_get_hi
        rts
gb_get_hi:
        sec
        sta zp_bits_hi
        jmp get_crunched_byte
.endif
; -------------------------------------------------------------------
; no code below this comment has to be modified in order to generate
; a working decruncher of this source file.
; However, you may want to relocate the tables last in the file to a
; more suitable address.
; -------------------------------------------------------------------

; -------------------------------------------------------------------
; jsr this label to decrunch, it will in turn init the tables and
; call the decruncher
; no constraints on register content, however the
; decimal flag has to be #0 (it almost always is, otherwise do a cld)
decrunch:

.if SHOW_PROGRESS_DURING_DECRUNCH = 1
        lda $FBB3
        cmp #$EA
        bne +
        lda #$A1 ; use ! instead of | for initial spinner animation
        sta progress_char+1
        sta progress_char+5
+
; -------------------------------------------------------------------
; show initial on-screen progress UI
;
        ldy #7
init_progress_loop:
        lda progress_char,y
        jsr show_one_progress_char
        dey
        bpl init_progress_loop
done_init_progress_loop:
.endif
; -------------------------------------------------------------------
; init zeropage, x and y regs. (12 bytes)
;
        ldy #0
        ldx #3
init_zp:
        jsr get_crunched_byte
        sta zp_bitbuf - 1,x
        dex
        bne init_zp
; -------------------------------------------------------------------
; calculate tables (62 bytes) + get_bits macro
; x and y must be #0 when entering
;
        clc
table_gen:
        tax
        tya
        and #$0f
        sta tabl_lo,y
        beq shortcut            ; start a new sequence
; -------------------------------------------------------------------
        txa
        adc tabl_lo - 1,y
        sta tabl_lo,y
        lda zp_len_hi
        adc tabl_hi - 1,y
shortcut:
        sta tabl_hi,y
; -------------------------------------------------------------------
        lda #$01
        sta <zp_len_hi
        lda #$78                ; %01111000
        mac_get_bits
; -------------------------------------------------------------------
        lsr
        tax
        beq rolled
        php
rolle:
        asl zp_len_hi
        sec
        ror
        dex
        bne rolle
        plp
rolled:
        ror
        sta tabl_bi,y
        bmi no_fixup_lohi
        lda zp_len_hi
        stx zp_len_hi
        .byte $24
no_fixup_lohi:
        txa
; -------------------------------------------------------------------
        iny
        cpy #encoded_entries
        bne table_gen
; -------------------------------------------------------------------
; prepare for main decruncher
        ldy zp_dest_lo
        stx zp_dest_lo
        stx zp_bits_hi
; -------------------------------------------------------------------
; copy one literal byte to destination (11(10) bytes)
;
.ifndef FORWARD_DECRUNCHING
  FORWARD_DECRUNCHING = 1
.endif
.if FORWARD_DECRUNCHING = 0
literal_start1:
        tya
        bne no_hi_decr
        dec zp_dest_hi
no_hi_decr:
        dey
        jsr get_crunched_byte
        sta (zp_dest_lo),y

.if SHOW_PROGRESS_DURING_DECRUNCH = 1
; periodically update on-screen progress UI
        dec progress_counter
        bne dont_update_progress_ui
        tya
        pha
        ldy progress_index
        lda progress_char,y
        jsr show_one_progress_char
        inc progress_index
        lda progress_index
        and #$07
        sta progress_index
        tay
        lda #$20
        jsr show_one_progress_char
        pla
        tay
dont_update_progress_ui:
.endif
.else
literal_start1:
        jsr get_crunched_byte
        sta (zp_dest_lo),y
        iny
        bne no_hi_incr
        inc zp_dest_hi
no_hi_incr:
.endif
; -------------------------------------------------------------------
; fetch sequence length index (15 bytes)
; x must be #0 when entering and contains the length index + 1
; when exiting or 0 for literal byte
next_round:
        dex
        lda zp_bitbuf
no_literal1:
        asl
        bne nofetch8
        jsr get_crunched_byte
        rol
nofetch8:
        inx
        bcc no_literal1
        sta zp_bitbuf
; -------------------------------------------------------------------
; check for literal byte (2 bytes)
;
        beq literal_start1
; -------------------------------------------------------------------
; check for decrunch done and literal sequences (4 bytes)
;
        cpx #$11
.ifdef INLINE_GET_BITS
        bcc skip_jmp
        jmp exit_or_lit_seq
skip_jmp:
.else
        bcs exit_or_lit_seq
.endif
; -------------------------------------------------------------------
; calulate length of sequence (zp_len) (18(11) bytes) + get_bits macro
;
        lda tabl_bi - 1,x
        mac_get_bits
        adc tabl_lo - 1,x       ; we have now calculated zp_len_lo
        sta zp_len_lo
.ifndef MAX_SEQUENCE_LENGTH_256
        lda zp_bits_hi
        adc tabl_hi - 1,x       ; c = 0 after this.
        sta zp_len_hi
; -------------------------------------------------------------------
; here we decide what offset table to use (27(26) bytes) + get_bits_nc macro
; z-flag reflects zp_len_hi here
;
        ldx zp_len_lo
.else
        tax
.endif
        lda #$e1
.ifdef EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
        cpx #$04
.else
        cpx #$03
.endif
        bcs gbnc2_next
        lda tabl_bit - 1,x
gbnc2_next:
        asl zp_bitbuf
        bne gbnc2_ok
        tax
        jsr get_crunched_byte
        rol
        sta zp_bitbuf
        txa
gbnc2_ok:
        rol
        bcs gbnc2_next
        tax
; -------------------------------------------------------------------
; calulate absolute offset (zp_src) (21(23) bytes) + get_bits macro
;
.ifndef MAX_SEQUENCE_LENGTH_256
        lda #0
        sta zp_bits_hi
.endif
        lda tabl_bi,x
        mac_get_bits
.if FORWARD_DECRUNCHING = 0
        adc tabl_lo,x
        sta zp_src_lo
        lda zp_bits_hi
        adc tabl_hi,x
        adc zp_dest_hi
.else
        clc
        adc tabl_lo,x
        eor #$ff
        sta zp_src_lo
        lda zp_dest_hi
        bcc skip_dest_hi
        sbc #1
        clc
skip_dest_hi:
        sbc zp_bits_hi
        sbc tabl_hi,x
        clc
.endif
        sta zp_src_hi
; -------------------------------------------------------------------
; prepare for copy loop (2 bytes)
;
pre_copy:
        ldx zp_len_lo
; -------------------------------------------------------------------
; main copy loop (30 bytes)
;
copy_next:
.if FORWARD_DECRUNCHING = 0
        tya
        bne copy_skip_hi
        dec zp_dest_hi
        dec zp_src_hi
copy_skip_hi:
        dey
.endif
.ifndef LITERAL_SEQUENCES_NOT_USED
        bcs get_literal_byte
.endif
        lda (zp_src_lo),y
literal_byte_gotten:
        sta (zp_dest_lo),y
.if (FORWARD_DECRUNCHING = 1)
        iny
        bne copy_skip_hi
        inc zp_dest_hi
        inc zp_src_hi
copy_skip_hi:
.endif
        dex
        bne copy_next
.ifndef MAX_SEQUENCE_LENGTH_256
        lda zp_len_hi
.ifdef INLINE_GET_BITS
        bne copy_next_hi
.endif
.endif
begin_stx:
        stx zp_bits_hi
.ifndef INLINE_GET_BITS
        beq next_round
.else
        jmp next_round
.endif
.ifndef MAX_SEQUENCE_LENGTH_256
copy_next_hi:
        dec zp_len_hi
        jmp copy_next
.endif
.ifndef LITERAL_SEQUENCES_NOT_USED
get_literal_byte:
        jsr get_crunched_byte
        bcs literal_byte_gotten
.endif
; -------------------------------------------------------------------
; exit or literal sequence handling (16(12) bytes)
;
exit_or_lit_seq:
.ifndef LITERAL_SEQUENCES_NOT_USED
        beq decr_exit
        jsr get_crunched_byte
.ifndef MAX_SEQUENCE_LENGTH_256
        sta zp_len_hi
.endif
        jsr get_crunched_byte
        tax
        bcs copy_next
decr_exit:
.endif
        rts
.ifdef EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
; -------------------------------------------------------------------
; the static stable used for bits+offset for lengths 1, 2 and 3 (3 bytes)
; bits 2, 4, 4 and offsets 64, 48, 32 corresponding to
; %10010000, %11100011, %11100010
tabl_bit:
        .byte $90, $e3, $e2
.else
; -------------------------------------------------------------------
; the static stable used for bits+offset for lengths 1 and 2 (2 bytes)
; bits 2, 4 and offsets 48, 32 corresponding to %10001100, %11100010
tabl_bit:
        .byte $8c, $e2
.endif
.if SHOW_PROGRESS_DURING_DECRUNCH = 1
progress_index:
        .byte $00
progress_counter:
        .byte $00
progress_char:
        .byte $DC, $FC, $AF, $AD, $DC, $FC, $AF, $AD
progress_address_lo:
        .byte $BB, $BC, $BD, $3D, $BD, $BC, $BB, $3B
progress_address_hi:
        .byte $05, $05, $05, $06, $06, $06, $06, $06
show_one_progress_char:
; in: A=ASCII char to show
;     y=0..7 index into progress_address_lo/hi array
        pha
        lda progress_address_lo,y
        sta progress_STA+1
        lda progress_address_hi,y
        sta progress_STA+2
        pla
progress_STA:
        sta $FFFF
        rts
.endif
; -------------------------------------------------------------------
; end of decruncher
; -------------------------------------------------------------------

; -------------------------------------------------------------------
; this 156 (204) byte table area may be relocated. It may also be
; clobbered by other data between decrunches.
; -------------------------------------------------------------------
decrunch_table=$200;;:
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;.IFDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;.ENDIF
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;        .byte 0,0,0,0,0,0,0,0,0,0,0,0
; -------------------------------------------------------------------
; end of decruncher
; -------------------------------------------------------------------
