home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip532.zip / amiga / flate.a < prev    next >
Text File  |  1997-04-20  |  16KB  |  440 lines

  1. ; Not copyrighted by Paul Kienitz, 20 June 94.  Last modified 21 Feb 96.
  2. ;
  3. ; 68000 assembly language version of inflate_codes(), for Amiga.  Prototype:
  4. ;
  5. ;   int inflate_codes(__GPRO__ struct huft *tl, struct huft *td,
  6. ;                     int bl, int bd);
  7. ;
  8. ; Where __GPRO__ expands to "struct Globals *G," if REENTRANT is defined,
  9. ; otherwise to nothing.  In the latter case G is a global variable.
  10. ;
  11. ; Define the symbol FUNZIP if this is for fUnZip.  It overrides REENTRANT.
  12. ;
  13. ; Define AZTEC to use the Aztec C macro version of getc() instead of the
  14. ; library getc() with FUNZIP.  AZTEC is ignored if FUNZIP is not defined.
  15. ;
  16. ; Define NO_CHECK_EOF to not use the fancy paranoid version of NEEDBITS --
  17. ; this is equivalent to removing the #define CHECK_EOF from inflate.c.
  18. ;
  19. ; Define INT16 if ints are short, otherwise it assumes ints are long.
  20. ;
  21. ; *DO NOT* define WSIZE -- this only works with the default value of 32K.
  22.  
  23.                 IFD     INT16
  24. MOVINT           MACRO
  25.         move.w          \1,\2
  26.                  ENDM
  27. INTSIZE equ     2
  28.                 ELSE    ; !INT16
  29. MOVINT           MACRO
  30.         move.l          \1,\2
  31.                  ENDM
  32. INTSIZE equ     4
  33.                 ENDC
  34.  
  35.                 IFD     REENTRANT
  36.                  IFND   FUNZIP
  37. REENT_G equ     1
  38.                  ENDC
  39.                 ENDC
  40.  
  41. ; struct huft is defined as follows:
  42. ;
  43. ;   struct huft {
  44. ;     uch e;                /* number of extra bits or operation */
  45. ;     uch b;                /* number of bits in this code or subcode */
  46. ;     union {
  47. ;       ush n;              /* literal, length base, or distance base */
  48. ;       struct huft *t;     /* pointer to next level of table */
  49. ;     } v;
  50. ;   };                      /* sizeof(struct huft) == 6 */
  51. ;
  52. ; so here we define the offsets of the various members of this struct:
  53.  
  54. h_e             equ     0
  55. h_b             equ     1
  56. h_n             equ     2
  57. h_t             equ     2
  58. SIZEOF_HUFT     equ     6
  59.  
  60. ; The following include file is generated from globals.h, and gives us equates
  61. ; that give the offsets in struct Globals of the fields we use, which are:
  62. ;       ulg bb
  63. ;       unsigned int bk, wp
  64. ;       (either array of or pointer to unsigned char) slide
  65. ; For fUnZip:
  66. ;       FILE *in
  67. ; For regular UnZip but not fUnZip:
  68. ;       int incnt, mem_mode
  69. ;       long csize
  70. ;       uch *inptr
  71. ; It also defines a value SIZEOF_slide, which tells us whether the appropriate
  72. ; slide field in G (either area.Slide or redirect_pointer) is a pointer or an
  73. ; array instance.  It is 4 in the former case and a large value in the latter.
  74. ; Lastly, this include will define CRYPT as 1 if appropriate.
  75.  
  76.                 IFD     FUNZIP
  77.         INCLUDE "amiga/G_offs.fa"
  78.                 ELSE
  79.         INCLUDE "amiga/G_offs.a"
  80.                 ENDC
  81.  
  82. ; G.bb is the global buffer that holds bits from the huffman code stream, which
  83. ; we cache in the register variable b.  G.bk is the number of valid bits in it,
  84. ; which we cache in k.  The macros NEEDBITS(n) and DUMPBITS(n) have side effects
  85. ; on b and k.
  86.  
  87.                 IFD     REENT_G
  88. G_SIZE  equ     4
  89. G_PUSH           MACRO          ; this macro passes "__G__" to functions
  90.         move.l          G,-(sp)
  91.                  ENDM
  92.                 ELSE
  93.         xref    _G              ; struct Globals
  94. G_SIZE  equ     0
  95. G_PUSH           MACRO
  96.         ds.b            0       ; does nothing; the assembler dislikes MACRO ENDM
  97.                  ENDM
  98.                 ENDC    ; REENT_G
  99.  
  100.         xref    _mask_bits      ; const ush near mask_bits[17];
  101.                 IFD     FUNZIP
  102.                  IF     CRYPT
  103.         xref    _encrypted      ; int -- boolean flag
  104.         xref    _update_keys    ; int update_keys(__GPRO__ int)
  105.         xref    _decrypt_byte   ; int decrypt_byte(__GPRO)
  106.                  ENDC   ; CRYPT
  107.                 ELSE    ; !FUNZIP
  108.         xref    _memflush       ; int memflush(__GPRO__ uch *, ulg)
  109.         xref    _readbyte       ; int readbyte(__GPRO)
  110.                 ENDC    ; FUNZIP
  111.  
  112.         xref    _getc           ; int getc(FILE *)
  113.         xref    _flush          ; if FUNZIP:  int flush(__GPRO__ ulg)
  114.                                 ; else:  int flush(__GPRO__ uch *, ulg *, int)
  115.  
  116. ; Here are our register variables.
  117.  
  118. b       equr    d2              ; ulg
  119. k       equr    d3              ; ush <= 32
  120. e       equr    d4              ; ush < 256 for most use
  121. w       equr    d5              ; unsigned int
  122. n       equr    d6              ; ush
  123. d       equr    d7              ; unsigned int
  124.  
  125. ; We always maintain w and d as valid unsigned longs, though they may be short.
  126.  
  127. t       equr    a2              ; struct huft *
  128. mask    equr    a3              ; ush *
  129. G       equr    a6              ; struct Globals *
  130.  
  131. ; Couple other items we need:
  132.  
  133. savregs reg     d2-d7/a2/a3/a6
  134.  
  135. WSIZE   equ     $8000           ; 32k... be careful not to treat as negative!
  136. EOF     equ     -1
  137.  
  138.                 IFD     FUNZIP
  139. ; This does getc(in).  Aztec version is based on #define getc(fp) in stdio.h
  140.  
  141.                  IFD    AZTEC
  142.         xref    __filbuf
  143. GETC              MACRO
  144.         move.l          in(G),a0
  145.         move.l          (a0),a1         ; in->_bp
  146.         cmp.l           4(a0),a1        ; in->_bend
  147.         blo.s           gci\@
  148.         move.l          a0,-(sp)
  149.         jsr             __filbuf
  150.         addq            #4,sp
  151.         bra.s           gce\@
  152. gci\@:  moveq           #0,d0           ; must be valid as longword
  153.         move.b          (a1)+,d0
  154.         move.l          a1,(a0)
  155. gce\@:
  156.                   ENDM
  157.                  ELSE   ; !AZTEC
  158. GETC              MACRO
  159.         move.l          in(G),-(sp)
  160.         jsr             _getc
  161.         addq            #4,sp
  162.                   ENDM
  163.                  ENDC   ; AZTEC
  164.                 ENDC    ; FUNZIP
  165.  
  166. ; Input depends on the NEXTBYTE macro.  This exists in three different forms.
  167. ; The first two are for fUnZip, with and without decryption.  The last is for
  168. ; regular UnZip with or without decryption.  The resulting byte is returned
  169. ; in d0 as a longword, and d1, a0, and a1 are clobbered.
  170.  
  171. ; FLUSH also has different forms for UnZip and fUnZip.  Arg must be a longword.
  172. ; The same scratch registers are trashed.
  173.  
  174.                 IFD     FUNZIP
  175.  
  176. NEXTBYTE         MACRO
  177.         GETC
  178.                   IF    CRYPT
  179.         tst.w           _encrypted+INTSIZE-2    ; test low word if long
  180.         beq.s           nbe\@
  181.         MOVINT          d0,-(sp)                ; save thru next call
  182.         G_PUSH
  183.         jsr             _decrypt_byte
  184.         eor.w           d0,G_SIZE+INTSIZE-2(sp) ; becomes arg to update_keys
  185.         jsr             _update_keys
  186.         addq            #INTSIZE+G_SIZE,sp
  187. nbe\@:
  188.                    IFEQ INTSIZE-2
  189.         ext.l           d0              ; assert -1 <= d0 <= 255
  190.                    ENDC
  191.                   ENDC  ; !CRYPT
  192.                  ENDM
  193.  
  194. FLUSH            MACRO
  195.         move.l          \1,-(sp)
  196.         G_PUSH
  197.         jsr             _flush
  198.         addq            #4+G_SIZE,sp
  199.                  ENDM
  200.  
  201.                 ELSE    ; !FUNZIP
  202.  
  203. NEXTBYTE         MACRO
  204. ;;        subq.l          #1,csize(G)
  205. ;;        bge.s           nbg\@
  206. ;;        moveq           #EOF,d0
  207. ;;        bra.s           nbe\@
  208. nbg\@:  subq.w          #1,incnt+INTSIZE-2(G)   ; treat as short
  209.         bge.s           nbs\@
  210.         G_PUSH
  211.         jsr             _readbyte
  212.                 IFNE    G_SIZE
  213.         addq            #G_SIZE,sp
  214.                 ENDC
  215.         bra.s           nbe\@
  216. nbs\@:  moveq           #0,d0
  217.         move.l          inptr(G),a0
  218.         move.b          (a0)+,d0
  219.         move.l          a0,inptr(G)
  220. nbe\@:
  221.                  ENDM
  222.  
  223. FLUSH            MACRO
  224.         MOVINT          #0,-(sp)                ; unshrink flag: always false
  225.         move.l          \1,-(sp)                ; length
  226.                   IFGT  SIZEOF_slide-4
  227.         pea             slide(G)                ; buffer to flush
  228.                   ELSE
  229.         move.l          slide(G),-(sp)
  230.                   ENDC
  231.         G_PUSH
  232.         tst.w           mem_mode+INTSIZE-2(G)   ; test lower word if long
  233.         beq.s           fm\@
  234.         jsr             _memflush               ; ignores the unshrink flag
  235.         bra.s           fe\@
  236. fm\@:   jsr             _flush
  237. fe\@:   lea             8+INTSIZE+G_SIZE(sp),sp
  238.                  ENDM
  239.  
  240.                 ENDC    ; ?FUNZIP
  241.  
  242. ; Here are the two bit-grabbing macros, defined in their NO_CHECK_EOF form:
  243. ;
  244. ;   #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}}
  245. ;   #define DUMPBITS(n) {b>>=(n);k-=(n);}
  246. ;
  247. ; Without NO_CHECK_EOF, NEEDBITS reads like this:
  248. ;
  249. ;   {while(k<(n)){int c=NEXTBYTE;if(c==EOF)return 1;b|=((ulg)c)<<k;k+=8;}}
  250. ;
  251. ; NEEDBITS clobbers d0, d1, a0, and a1, none of which can be used as the arg
  252. ; to the macro specifying the number of bits.  The arg can be a shortword memory
  253. ; address, or d2-d7.  The result is copied into d1 as a word ready for masking.
  254. ; DUMPBITS has no side effects; the arg must be a d-register (or immediate in the
  255. ; range 1-8?) and only the lower byte is significant.
  256.  
  257. NEEDBITS        MACRO
  258. nb\@:   cmp.w           \1,k            ; assert 0 < k <= 32 ... arg may be 0
  259.         bhs.s           ne\@
  260.         NEXTBYTE                        ; returns in d0.l
  261.                  IFND   NO_CHECK_EOF
  262.         cmp.w           #EOF,d0
  263.         bne.s           nok\@
  264.         moveq           #1,d0           ; PK_WARN?
  265.         bra             return
  266.                  ENDC   ; !NO_CHECK_EOF
  267. nok\@:  lsl.l           k,d0
  268.         or.l            d0,b
  269.         addq.w          #8,k
  270.         bra.s           nb\@
  271. ne\@:   move.w          b,d1
  272.                 ENDM
  273.  
  274. DUMPBITS        MACRO
  275.         lsr.l           \1,b            ; upper bits of \1 are ignored??
  276.         sub.b           \1,k
  277.                 ENDM
  278.  
  279.  
  280. ; ******************************************************************************
  281. ; Here we go, finally:
  282.  
  283.         xdef    _inflate_codes
  284.  
  285. _inflate_codes:
  286.         link            a5,#-4
  287.         movem.l         savregs,-(sp)
  288. ; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18|20(a5) = bd... add 4 for REENT_G
  289. ; -2(a5) = ml, -4(a5) = md.  Here we cache some globals and args:
  290.                 IFD     REENT_G
  291.         move.l          8(a5),G
  292.                 ELSE
  293. ;;      move.l          _G,G            ; old global pointer version
  294.         lea             _G,G            ; G is now a global instance
  295.                 ENDC
  296.         lea             _mask_bits,mask
  297.         move.l          bb(G),b
  298.         MOVINT          bk(G),k
  299.                 IFD     INT16
  300.         moveq           #0,w            ; keep this usable as longword
  301.                 ENDC
  302.         MOVINT          wp(G),w
  303.         moveq           #0,e            ; keep this usable as longword too
  304.         MOVINT          16+G_SIZE(a5),d0
  305.         add.w           d0,d0
  306.         move.w          (mask,d0.w),-2(a5)      ; ml = mask_bits[bl]
  307.         MOVINT          16+INTSIZE+G_SIZE(a5),d0
  308.         add.w           d0,d0
  309.         move.w          (mask,d0.w),-4(a5)      ; md = mask_bits[bd]
  310.  
  311. main_loop:
  312.         NEEDBITS        14+INTSIZE+G_SIZE(a5)   ; bl, lower word if long
  313.         and.w           -2(a5),d1               ; ml
  314.         mulu            #SIZEOF_HUFT,d1
  315.         move.l          8+G_SIZE(a5),a0         ; tl
  316.         lea             (a0,d1.l),t
  317.         move.b          h_e(t),e
  318.         cmp.w           #16,e
  319.         bls.s           topdmp
  320. intop:   moveq          #1,d0
  321.          cmp.w          #99,e
  322.          beq            return          ; error in zipfile
  323.          move.b         h_b(t),d0
  324.          DUMPBITS       d0
  325.          sub.w          #16,e
  326.          NEEDBITS       e
  327.          move.w         e,d0
  328.          add.w          d0,d0
  329.          and.w          (mask,d0.w),d1
  330.          mulu           #SIZEOF_HUFT,d1
  331.          move.l         h_t(t),a0
  332.          lea            (a0,d1.l),t
  333.          move.b         h_e(t),e
  334.          cmp.w          #16,e
  335.          bgt.s          intop
  336. topdmp: move.b          h_b(t),d0
  337.         DUMPBITS        d0
  338.  
  339.         cmp.w           #16,e           ; is this huffman code a literal?
  340.         bne             lenchk          ; no
  341.         move.w          h_n(t),d0       ; yes
  342.                 IFGT    SIZEOF_slide-4
  343.         lea             slide(G),a0
  344.                 ELSE
  345.         move.l          slide(G),a0
  346.                 ENDC
  347.         move.b          d0,(a0,w.l)     ; stick in the decoded byte
  348.         addq.w          #1,w
  349.         cmp.w           #WSIZE,w
  350.         blo             main_loop
  351.         FLUSH           w
  352.         moveq           #0,w
  353.         bra             main_loop       ; do some more
  354.  
  355. lenchk: cmp.w           #15,e           ; is it an end-of-block code?
  356.         beq             finish          ; if yes, we're done
  357.         NEEDBITS        e               ; no: we have a duplicate string
  358.         move.w          e,d0
  359.         add.w           d0,d0
  360.         and.w           (mask,d0.w),d1
  361.         move.w          h_n(t),n
  362.         add.w           d1,n            ; length of block to copy
  363.         DUMPBITS        e
  364.         NEEDBITS        14+(2*INTSIZE)+G_SIZE(a5)       ; bd, lower word if long
  365.         and.w           -4(a5),d1                       ; md
  366.         mulu            #SIZEOF_HUFT,d1
  367.         move.l          12+G_SIZE(a5),a0                ; td
  368.         lea             (a0,d1.l),t
  369.         move.b          h_e(t),e
  370.         cmp.w           #16,e
  371.         bls.s           middmp
  372. inmid:   moveq          #1,d0
  373.          cmp.w          #99,e
  374.          beq            return          ; error in zipfile
  375.          move.b         h_b(t),d0
  376.          DUMPBITS       d0
  377.          sub.w          #16,e
  378.          NEEDBITS       e
  379.          move.w         e,d0
  380.          add.w          d0,d0
  381.          and.w          (mask,d0.w),d1
  382.          mulu           #SIZEOF_HUFT,d1
  383.          move.l         h_t(t),a0
  384.          lea            (a0,d1.l),t
  385.          move.b         h_e(t),e
  386.          cmp.w          #16,e
  387.          bgt.s          inmid
  388. middmp: move.b          h_b(t),d0
  389.         DUMPBITS        d0
  390.         NEEDBITS        e
  391.         move.w          e,d0
  392.         add.w           d0,d0
  393.         and.w           (mask,d0.w),d1
  394.         move.l          w,d
  395.         sub.w           h_n(t),d
  396.         sub.w           d1,d            ; distance back to block to copy
  397.         DUMPBITS        e
  398.  
  399. indup:   move.w         #WSIZE,e        ; violate the e < 256 rule
  400.          and.w          #WSIZE-1,d
  401.          cmp.w          d,w
  402.          blo.s          ddgw
  403.           sub.w         w,e
  404.          bra.s          dadw
  405. ddgw:     sub.w         d,e
  406. dadw:    cmp.w          n,e
  407.          bls.s          delen
  408.           move.w        n,e
  409. delen:   sub.w          e,n             ; size of sub-block to copy
  410.                 IFGT    SIZEOF_slide-4
  411.          lea            slide(G),a0
  412.                 ELSE
  413.          move.l         slide(G),a0
  414.                 ENDC
  415.          move.l         a0,a1
  416.          add.l          w,a0            ; w and d are valid longwords
  417.          add.l          d,a1
  418.          move.w         e,d0
  419.          subq           #1,d0           ; assert >= 0 if sign extended
  420. dspin:    move.b        (a1)+,(a0)+     ; string is probably short, so
  421.           dbra          d0,dspin        ; don't use any fancier copy method
  422.          add.w          e,w
  423.          add.w          e,d
  424.          cmp.w          #WSIZE,w
  425.          blo.s          dnfl
  426.          FLUSH          w
  427.          moveq          #0,w
  428. dnfl:    tst.w          n               ; need to do more sub-blocks?
  429.          bne            indup           ; yes
  430.         moveq           #0,e            ; restore zeroness in upper bytes
  431.         bra             main_loop       ; do some more
  432.  
  433. finish: MOVINT          w,wp(G)         ; restore cached globals
  434.         MOVINT          k,bk(G)
  435.         move.l          b,bb(G)
  436.         moveq           #0,d0           ; return "no error"
  437. return: movem.l         (sp)+,savregs
  438.         unlk            a5
  439.         rts
  440.