;
; Copyright © 1991, 1992 by Walter Rothe. You may freely use and modify this
; program, but not for commercial profit. A modest fee for distribution is
; allowed. Derivative works must be released with source along with the
; executable or provisions made to provide the user source, if requested.
; Uploading source to a major bulletin board system within 6 months of the
; time of the request satisfies this requirement. This copyright notice
; must not be deleted from the source.
;
;:ts=8
        far     data
        machine mc68020
;/* decodes up to 'count' chars (but no more than WinSiz) into supplied
;buffer; returns actual count.  */
;
;#include "lh5.h"
;#define NP (DICBIT + 1)
;#define NT (CODE_BIT + 3)
;extern BufRead(), read_pt_len(), read_c_len();
;extern long BCount, HWinSiz, WinSiz;
;extern ulong bitbuf;
;extern int bitcount, decoded;
;extern uint jb, blocksize;
;extern ushort left[], right[], c_table[], pt_table[], LZBuf[];
;extern uchar c_len[], pt_len[];
;
;long decodeit( count, buffer)
;uint count;
;uchar buffer[];
;{
        xdef    _decodeit
_decodeit:
        link    a5,#.2
        movem.l .3,-(sp)
;   static uchar *savepi;
        bss     .10001,4
;   register uint i;
;   register ulong bitbfr = bitbuf;
;   register int ct = bitcount, n;
;   uint mask;
;   uchar *bstrt  = &buffer[0], *bend = &buffer[count];
;   uchar *bguard = &buffer[WinSiz - 258], *blst = &buffer[WinSiz - 1];
;   register uchar *bufpi  = savepi, *bufpr = bstrt;
;   register uchar *bufend = bstrt + jb;
;   register uint blksz = blocksize;
;   register ushort *inbf = &LZBuf[ BCount ];
;   ushort *winend = &LZBuf[ HWinSiz ];
;
;   while (bufpr < bufend) {
        move.l  _bitbuf,d3
        move.l  _bitcount,d4
        move.l  12(a5),-8(a5)
        move.l  8(a5),d0
        add.l   12(a5),d0
        move.l  d0,-12(a5)
        move.l  12(a5),-16(a5)
        move.l  -16(a5),a0
        add.l   _WinSiz,a0
        move.l  a0,-16(a5)
        sub.l   #258,-16(a5)
        move.l  12(a5),-20(a5)
        move.l  -20(a5),a0
        add.l   _WinSiz,a0
        move.l  a0,-20(a5)
        sub.l   #1,-20(a5)
        move.l  .10001,a2
        move.l  -8(a5),a3
        move.l  _jb,d6
        add.l   -8(a5),d6
        move.l  _blocksize,d7
        move.l  _BCount,d0
        add.l   d0,d0
        lea.l   _LZBuf,a1
        add.l   d0,a1
        move.l  _HWinSiz,d0
        add.l   d0,d0
        lea.l   _LZBuf,a0
        add.l   a0,d0
        move.l  d0,-28(a5)
; Clear upper half of d2 and it should not be modified
        move.l  #0,d2
        move.l  #0,d5
.10002
        cmp.l   d6,a3
        bcc     .10003
;      *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;      if( bufpi > blst ) bufpi = bstrt;
        cmp.l   -20(a5),a2
        bls     .10004
        move.l  -8(a5),a2
;      if (bufpr == bend) goto savret;
.10004
        cmp.l   -12(a5),a3
        beq     .10005
;   }
        bra     .10002
.10003
;   for ( ; ; ) {
.10006
;      /* decode character */
;      if (--blksz == 0) {
        sub.l   #1,d7
        bne     .10008
;         bitbuf = bitbfr; bitcount = ct; BCount = (inbf - &LZBuf[0]);
        move.l  d3,_bitbuf
        move.l  d4,_bitcount
        sub.l   #_LZBuf,a1
        move.l  a1,d0
        lsr.l   #1,d0
        move.l  d0,_BCount
;         blksz = getbits(16);
        pea     16
        jsr     _getbits
        move.l  d0,d7
;         if (blksz == 0) {
        tst.l   d7
        add.w   #4,sp
        bne     .10009
;            blocksize = blksz; savepi = bufpi; jb = bufend - bufpr; return 0;
        move.l  d7,_blocksize
        move.l  a2,.10001
        move.l  d6,d0
        sub.l   a3,d0
        move.l  d0,_jb
        move.l  #0,d0
.4
        movem.l (sp)+,.3
        unlk    a5
        rts
;         }
;         read_pt_len(NT, 5, 3); /* 5=smallest int so that 1<<5 > NT */
.10009
        pea     3
        pea     5
        pea     19
        jsr     _read_pt_len
;         read_c_len();
        jsr     _read_c_len
;         read_pt_len(NP, 4, -1); /* 4=smallest int so that 1<<4 > NP */
        pea     -1
        pea     4
        pea     14
        jsr     _read_pt_len
;         bitbfr = bitbuf; ct = bitcount; inbf = &LZBuf[ BCount ];
        move.l  _bitbuf,d3
        move.l  _bitcount,d4
        move.l  _BCount,a1
        add.l   a1,a1
        add.l   #_LZBuf,a1
;      }
;      i = c_table[bitbfr >> (BITBUFSIZ - 12)];
        lea     24(sp),sp
.10008
        move.l  d3,d0
        move.l  #20,d1
        lsr.l   d1,d0
        add.l   d0,d0
        lea     _c_table,a0
        move.w  (a0,d0.w),d2
;      if (i >= NC) {
        cmp.l   #510,d2
        bcs     .10010
;         mask = (unsigned) 1 << (BITBUFSIZ - 1 - 12);
        move.l  #524288,-4(a5)
;         do {
.10013
;            if (bitbfr & mask) i = right[i];
        move.l  d3,d0
        and.l   -4(a5),d0
        beq     .10014
        move.l  d2,d0
        add.l   d0,d0
        lea     _right,a0
        move.l  #0,d1
        move.w  (a0,d0.l),d1
        move.l  d1,d2
;            else               i = left [i];
        bra     .10015
.10014
        move.l  d2,d0
        add.l   d0,d0
        lea     _left,a0
        move.l  #0,d1
        move.w  (a0,d0.l),d1
        move.l  d1,d2
.10015
;            mask >>= 1;
        move.l  -4(a5),d0
        lsr.l   #1,d0
        move.l  d0,-4(a5)
;         } while (i >= NC);
.10011
        cmp.l   #510,d2
        bcc     .10013
.10012
;      }
;      n = c_len[i];
.10010
        lea     _c_len,a0
        move.b  (a0,d2.w),d5
;      bitbfr <<= n;
        asl.l   d5,d3
;      ct += n;
        add.l   d5,d4
;      if ( ct >= 16) {
        cmp.l   #16,d4
        blt     .10016
;         ct -= 16;
        sub.l   #16,d4
;         if( inbf == winend ) { BufRead(); inbf = &LZBuf[0]; }
        cmp.l   -28(a5),a1
        bne     .10017
        jsr     _BufRead
        lea.l   _LZBuf,a1
;         bitbfr = ( *inbf++ | ((bitbfr >> ct) & 0xffff0000)) << ct;
.10017
        lsr.l   d4,d3
        move.w  (a1)+,d3
        asl.l   d4,d3
;      }
;      if (i <= UCHAR_MAX) { *bufpr++ = i; if( bufpr == bend) goto savret; }
.10016
        cmp.l   #255,d2
        bhi     .10018
        move.b  d2,(a3)+
        cmp.l   -12(a5),a3
        bne     .10006
;      else {
        bra     .10005
.10018
;         bufend = bufpr + i - (UCHAR_MAX + 1 - THRESHOLD);
        move.l  d2,d6
        add.l   a3,d6
        add.l   #-253,d6
;         /* decode position */
;         i = pt_table[bitbfr >> (BITBUFSIZ - 8)];
        move.l  d3,d0
        move.l  #24,d1
        lsr.l   d1,d0
        add.l   d0,d0
        lea     _pt_table,a0
        move.w  (a0,d0.w),d2
;         if (i >= NP) {
        cmp.l   #14,d2
        bcs     .10020
;            mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
        move.l  #8388608,-4(a5)
;            do {
.10023
;               if (bitbfr & mask) i = right[i];
        move.l  d3,d0
        and.l   -4(a5),d0
        beq     .10024
        move.l  d2,d0
        add.l   d0,d0
        lea     _right,a0
        move.l  #0,d1
        move.w  (a0,d0.l),d1
        move.l  d1,d2
;               else               i = left [i];
        bra     .10025
.10024
        move.l  d2,d0
        add.l   d0,d0
        lea     _left,a0
        move.l  #0,d1
        move.w  (a0,d0.l),d1
        move.l  d1,d2
.10025
;               mask >>= 1;
        move.l  -4(a5),d0
        lsr.l   #1,d0
        move.l  d0,-4(a5)
;            } while (i >= NP);
.10021
        cmp.l   #14,d2
        bcc     .10023
.10022
;         }
;         n = pt_len[i];
.10020
        lea     _pt_len,a0
        move.b  (a0,d2.w),d5
;         bitbfr <<= n;
        asl.l   d5,d3
;         ct += n;
        add.l   d5,d4
;         if ( ct >= 16) {
        cmp.l   #16,d4
        blt     .10026
;            ct -= 16;
        sub.l   #16,d4
;            if( inbf == winend ) { BufRead(); inbf = &LZBuf[0]; }
        cmp.l   -28(a5),a1
        bne     .10027
        jsr     _BufRead
        lea.l   _LZBuf,a1
;            bitbfr = ( *inbf++ | ((bitbfr >> ct) & 0xffff0000)) << ct;
.10027
        lsr.l   d4,d3
        move.w  (a1)+,d3
        asl.l   d4,d3
;         }
;         if (i != 0) {
.10026
        tst.l   d2
        beq     .10028
;            n = i - 1;
        move.l  d2,d5
        sub.l   #1,d5
;            i = ((unsigned) 1 << n) + (bitbfr >> (BITBUFSIZ - n));
;            bitbfr <<= n;
        move.l  d3,d2
        rol.l   d5,d2
        lsl.l   d5,d3
        eor.l   d3,d2
        bset.l  d5,d2
;            ct += n;
        add.l   d5,d4
;            if ( ct >= 16) {
        cmp.l   #16,d4
        blt     .10029
;               ct -= 16;
        sub.l   #16,d4
;               if( inbf == winend ) { BufRead(); inbf = &LZBuf[0]; }
        cmp.l   -28(a5),a1
        bne     .10030
        jsr     _BufRead
        lea.l   _LZBuf,a1
;               bitbfr = ( *inbf++ | ((bitbfr >> ct) & 0xffff0000))<<ct;
.10030
        lsr.l   d4,d3
        move.w  (a1)+,d3
        asl.l   d4,d3
;            }
;         }
.10029
;         bufpi = bufpr - i - 1;
.10028
        move.l  a3,a2
        sub.l   d2,a2
        add.l   #-1,a2
;         if( bufpi >= bstrt ) {
        cmp.l   -8(a5),a2
        bcs     .10031
;            if( bufend < bend ) {
        cmp.l   -12(a5),d6
        bcc     .10032
;               *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;               *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;               do *bufpr++ = *bufpi++; while (bufpr < bufend);
.10035
        move.b  (a2)+,(a3)+
        cmp.l   d6,a3
        bcs     .10035
;            }
;            else { while( bufpr < bend ) *bufpr++ = *bufpi++; goto savret; }
        bra     .10006
.10032
        cmp.l   -12(a5),a3
        bcc     .10005
        move.b  (a2)+,(a3)+
        bra     .10032
;         }
;         else {
.10031
;            bufpi += WinSiz;
        add.l   _WinSiz,a2
;            if( bufpi < bguard ) {
        cmp.l   -16(a5),a2
        bcc     .10040
;               if( bufend < bend ) {
        cmp.l   -12(a5),d6
        bcc     .10041
;                  *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;                  *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;                  do *bufpr++ = *bufpi++; while (bufpr < bufend);
.10044
        move.b  (a2)+,(a3)+
        cmp.l   d6,a3
        bcs     .10044
;               }
;               else { while( bufpr < bend ) *bufpr++ = *bufpi++; goto savret; }
        bra     .10006
.10041
        cmp.l   -12(a5),a3
        bcc     .10005
        move.b  (a2)+,(a3)+
        bra     .10041
;            }
;            else {
.10040
;               while (bufpr < bufend) {
.10049
        cmp.l   d6,a3
        bcc     .10006
;                  *bufpr++ = *bufpi++;
        move.b  (a2)+,(a3)+
;                  if( bufpi > blst ) bufpi = bstrt;
        cmp.l   -20(a5),a2
        bls     .10051
        move.l  -8(a5),a2
;                  if (bufpr == bend) goto savret;
.10051
        cmp.l   -12(a5),a3
        beq     .10005
;               }
        bra     .10049
;            }
;         }
;      }
;   }
;   savret: bitbuf = bitbfr; bitcount = ct; jb = bufend - bufpr;
.10005
        move.l  d3,_bitbuf
        move.l  d4,_bitcount
        move.l  d6,d0
        sub.l   a3,d0
        move.l  d0,_jb
;   BCount = (inbf - &LZBuf[0]);
        sub.l   #_LZBuf,a1
        move.l  a1,d0
        asr.l   #1,d0
        move.l  d0,_BCount
;   savepi = bufpi; blocksize = blksz;
        move.l  a2,.10001
        move.l  d7,_blocksize
;   return (long)(bufpr - bstrt);
        move.l  a3,d0
        sub.l   -8(a5),d0
        bra     .4
;}
.2      equ     -28
.3      reg     d2/d3/d4/d5/d6/d7/a2/a3
;
        xref    _read_c_len
        xref    _read_pt_len
        xref    _BufRead
        xref    _getbits
        xref    .begin
        dseg
        xref    _pt_len
        xref    _c_len
        xref    _LZBuf
        xref    _pt_table
        xref    _c_table
        xref    _blocksize
        xref    _jb
        xref    _bitcount
        xref    _HWinSiz
        xref    _WinSiz
        xref    _BCount
        xref    _right
        xref    _left
        xref    _bitbuf
        end
