;
; 2001-11-18, Piotr Fusik
; 2018-05-20, Christian Kruger
;
; unsigned long __fastcall__ adler32 (unsigned long adler, unsigned char* buf,
;                                     unsigned len);
;

        .export _adler32

        .import         incsp2, incsp4, popptr1, popeax
        .importzp       sreg, ptr1, ptr2, tmp1

BASE    =       65521   ; largest prime smaller than 65536

_adler32:
; ptr2 = (len & 0xff) == 0 ? len : len + 0x100;
        tay
        beq     @L1
        inx
@L1:    sta     ptr2
        stx     ptr2+1
; ptr1 = buf
        jsr     popptr1
; if (buf == NULL) return 1L;
        ora     ptr1+1
        beq     @L0
; s1 = adler & 0xFFFF; s2 = adler >> 16;
        jsr     popeax
; if (len == 0) return adler;
        ldy     ptr2
        bne     @L2
        ldy     ptr2+1
        beq     @RET
@L2:    ldy     #0
; s1 += *ptr++; if (s1 >= BASE) s1 -= BASE;
@L3:    clc
        adc     (ptr1),y
        bcc     @L4
        inx
        beq     @L5     ; C flag is set
@L4:    cpx     #>BASE
        bcc     @L6
        cmp     #<BASE
        bcc     @L6
        inx             ; ldx #0
@L5:    sbc     #<BASE  ; C flag is set
        clc
@L6:    sta     tmp1
; s2 += s1; if (s2 >= BASE) s2 -= BASE;
        adc     sreg    ; C flag is clear
        sta     sreg
        txa
        adc     sreg+1
        sta     sreg+1
        bcs     @L7
        cmp     #>BASE
        bcc     @L8
        lda     sreg
        cmp     #<BASE
        bcc     @L8
@L7:    lda     sreg
        sbc     #<BASE  ; C flag is set
        sta     sreg
        lda     sreg+1
        sbc     #>BASE
        sta     sreg+1
@L8:    lda     tmp1
        iny
        bne     @L9
        inc     ptr1+1
@L9:    dec     ptr2
        bne     @L3
        dec     ptr2+1
        bne     @L3
; return (s2 << 16) | s1;
@RET:   rts

; return 1L
@L0:    sta     sreg
        sta     sreg+1
        tax             ; (popptr1 doesn't set .X)
        lda     #1
; ignore adler
        jmp     incsp4
