📄 flate.a
字号:
; Not copyrighted by Paul Kienitz, 20 Jun 94.;; Assembly language version of inflate_codes(), for Amiga. Prototype:;; int flate_codes(struct huft *tl, struct huft *td, int bl, int bd,; unsigned char *slide);;; It is called by defining inflate_codes(tl, td, bl, bd) as; flate_codes(tl, td, bl, bd, slide).;; Define the symbol FUNZIP if this is for fUnZip. Define CRYPT if this is; for fUnZip with decryption enabled. Define AZTEC to use the Aztec C; buffered input macro instead of the library getc() with FUNZIP.;; => int MUST BE 16 BITS!!! <= => WSIZE MUST BE 32K! <=;; struct huft is defined as follows:;; struct huft {; uch e; /* number of extra bits or operation */; uch b; /* number of bits in this code or subcode */; union {; ush n; /* literal, length base, or distance base */; struct huft *t; /* pointer to next level of table */; } v;; }; /* sizeof(struct huft) == 6 */;; so here we define the offsets of the various members of this struct:h_e equ 0h_b equ 1h_n equ 2h_t equ 2SIZEOF_HUFT equ 6; There are several global variables we need to access. Their definitions:;; unsigned long bb;; unsigned int bk, wp;; unsigned short mask[17];; FILE *in;; int encrypted; /* FUNZIP CRYPT only */;; int incnt, mem_mode; /* non-FUNZIP only */; long csize; /* non-FUNZIP only */; unsigned long outcnt; /* non-FUNZIP only */; unsigned char *inptr; /* non-FUNZIP only */;; bb is the global buffer that holds bits from the huffman code stream, which; we cache in the register variable b. bk is the number of valid bits in it,; which we cache in k. The macros NEEDBITS(n) and DUMPBITS(n) have side effects; on b and k. xref _bb xref _bk xref _mask xref _wp IFD FUNZIP IFD CRYPT xref _encrypted xref _update_keys ; int update_keys(int) xref _decrypt_byte ; int decrypt_byte(void) ENDC ; CRYPT xref _in xref _getc ; int getc(FILE *) ELSE ; !FUNZIP xref _csize xref _incnt xref _mem_mode xref _inptr xref _readbyte ; int readbyte(void) ENDC xref _flush ; if FUNZIP: int flush(unsigned long) ; ...if !FUNZIP: int flush(unsigned char *, unsigned long *, int); Here are our register variables. Remember that int == short!b equr d2 ; unsigned longk equr d3 ; unsigned int <= 32e equr d4 ; unsigned int < 256 for most usew equr d5 ; unsigned intn equr d6 ; unsigned intd equr d7 ; unsigned int; assert: we always maintain w and d as valid unsigned longs.t equr a2 ; struct huft *slide equr a3 ; unsigned char *mask equr a6 ; unsigned short *; Couple other items we need:savregs reg d2-d7/a2/a3/a6WSIZE equ $8000 ; 32k... be careful not to treat as negative! IFD FUNZIP; This does getc(in). Aztec version is based on #define getc(fp) in stdio.h IFD AZTEC xref __filbufGETC MACRO move.l _in,a0 move.l (a0),a1 ; in->_bp cmp.l 4(a0),a1 ; in->_bend blo.s gci\@ move.l a0,-(sp) jsr __filbuf addq #4,sp bra.s gce\@gci\@: moveq #0,d0 ; must be valid as longword move.b (a1)+,d0 move.l a1,(a0)gce\@: ENDM ELSE ; !AZTECGETC MACRO move.l _in,-(sp) jsr _getc addq #4,sp ENDM ENDC ; AZTEC ENDC ; FUNZIP; Input depends on the NEXTBYTE macro. This exists in three different forms.; The first two are for fUnZip, with and without decryption. The last is for; regular UnZip with or without decryption. The resulting byte is returned; in d0 as a longword, and d1, a0, and a1 are clobbered. IFD FUNZIP IFD CRYPTNEXTBYTE MACRO GETC tst.w _encrypted beq.s nbe\@ move.w d0,-(sp) ; save thru next call jsr _decrypt_byte eor.w d0,(sp) ; becomes arg to update_keys jsr _update_keys addq #2,spnbe\@: ext.l d0 ; assert -1 <= d0 <= 255 ENDM ELSE ; !CRYPTNEXTBYTE MACRO GETC ; nothing else in this case ENDM ENDC ELSE ; !FUNZIPNEXTBYTE MACRO subq.l #1,_csize bge.s nbg\@ moveq #-1,d0 ; return EOF bra.s nbe\@nbg\@: subq.w #1,_incnt bge.s nbs\@ jsr _readbyte bra.s nbe\@nbs\@: moveq #0,d0 move.l _inptr,a0 move.b (a0)+,d0 move.l a0,_inptrnbe\@: ENDM ENDC; FLUSH has different versions for fUnZip and UnZip. Arg must be a longword. IFD FUNZIPFLUSH MACRO move.l \1,-(sp) jsr _flush addq #4,sp ENDM ELSE ; !FUNZIP xref _mem_mode xref _outcntFLUSH MACRO tst.w _mem_mode bne.s fm\@ move.w #0,-(sp) ; unshrink flag: always false move.l \1,-(sp) ; length move.l slide,-(sp) ; buffer to flush jsr _flush lea 10(sp),sp bra.s fe\@fm\@: move.l w,_outcntfe\@: ENDM ENDC ; FUNZIP; Here are the two bit-grabbing macros, defined in their non-CHECK_EOF form:;; define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}}; define DUMPBITS(n) {b>>=(n);k-=(n);};; NEEDBITS clobbers d0, d1, a0, and a1, none of which can be used as the arg; to the macro specifying the number of bits. The arg can be a shortword memory; address, or d2-d7. The result is copied into d1 as a word ready for masking.; DUMPBITS has no side effects; the arg must be a d-register (or immediate in the; range 1-8?) and only the lower byte is significant.NEEDBITS MACROnb\@: cmp.w \1,k ; assert 0 < k <= 32 ... arg may be 0 bhs.s ne\@ NEXTBYTE ; returns in d0.l lsl.l k,d0 or.l d0,b addq.w #8,k bra.s nb\@ne\@: move.w b,d1 ENDMDUMPBITS MACRO lsr.l \1,b ; upper bits of \1 are ignored?? sub.b \1,k ENDM; ******************************************************************************; Here we go, finally: xdef _flate_codes ; (pointer, pointer, int, int, pointer)_flate_codes: link a5,#-4 movem.l savregs,-(sp); 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18(a5) = bd, 20(a5) = slide,; -2(a5) = ml, -4(a5) = md. Here we cache some globals and args: move.l 20(a5),slide lea _mask,mask move.l _bb,b move.w _bk,k moveq #0,w ; keep this usable as longword move.w _wp,w moveq #0,e ; keep this usable as longword too move.w 16(a5),d0 add.w d0,d0 move.w (mask,d0.w),-2(a5) ; ml = mask[bl] move.w 18(a5),d0 add.w d0,d0 move.w (mask,d0.w),-4(a5) ; md = mask[bd]main_loop: NEEDBITS 16(a5) ; bl and.w -2(a5),d1 ; ml mulu #SIZEOF_HUFT,d1 move.l 8(a5),a0 ; tl lea (a0,d1.l),t move.b h_e(t),e cmp.w #16,e bls.s topdmpintop: moveq #1,d0 cmp.w #99,e beq return ; error in zipfile move.b h_b(t),d0 DUMPBITS d0 sub.w #16,e NEEDBITS e move.w e,d0 add.w d0,d0 and.w (mask,d0.w),d1 mulu #SIZEOF_HUFT,d1 move.l h_t(t),a0 lea (a0,d1.l),t move.b h_e(t),e cmp.w #16,e bgt.s intoptopdmp: move.b h_b(t),d0 DUMPBITS d0 cmp.w #16,e ; is this huffman code a literal? bne lenchk ; no move.w h_n(t),d0 ; yes move.b d0,(slide,w.l) ; stick in the decoded byte addq.w #1,w cmp.w #WSIZE,w blo main_loop FLUSH w moveq #0,w bra main_loop ; do some morelenchk: cmp.w #15,e ; is it an end-of-block code? beq finish ; if yes, we're done NEEDBITS e ; no: we have a duplicate string move.w e,d0 add.w d0,d0 and.w (mask,d0.w),d1 move.w h_n(t),n add.w d1,n ; length of block to copy DUMPBITS e NEEDBITS 18(a5) ; bd and.w -4(a5),d1 ; md mulu #SIZEOF_HUFT,d1 move.l 12(a5),a0 ; td lea (a0,d1.l),t move.b h_e(t),e cmp.w #16,e bls.s middmpinmid: moveq #1,d0 cmp.w #99,e beq return ; error in zipfile move.b h_b(t),d0 DUMPBITS d0 sub.w #16,e NEEDBITS e move.w e,d0 add.w d0,d0 and.w (mask,d0.w),d1 mulu #SIZEOF_HUFT,d1 move.l h_t(t),a0 lea (a0,d1.l),t move.b h_e(t),e cmp.w #16,e bgt.s inmidmiddmp: move.b h_b(t),d0 DUMPBITS d0 NEEDBITS e move.w e,d0 add.w d0,d0 and.w (mask,d0.w),d1 move.l w,d sub.w h_n(t),d sub.w d1,d ; distance back to block to copy DUMPBITS eindup: move.w #WSIZE,e ; violate the e < 256 rule and.w #WSIZE-1,d cmp.w d,w blo.s ddgw sub.w w,e bra.s dadwddgw: sub.w d,edadw: cmp.w n,e bls.s delen move.w n,edelen: sub.w e,n ; size of sub-block to copy move.l slide,a0 move.l a0,a1 add.l w,a0 ; w and d are valid longwords add.l d,a1 move.w e,d0 subq #1,d0 ; assert >= 0 if sign extendeddspin: move.b (a1)+,(a0)+ ; string is probably short, so dbra d0,dspin ; don't use any fancier copy method add.w e,w add.w e,d cmp.w #WSIZE,w blo.s dnfl FLUSH w moveq #0,wdnfl: tst.w n ; need to do more sub-blocks? bne indup ; yes moveq #0,e ; restore zeroness in upper bytes bra main_loop ; do some morefinish: move.w w,_wp ; restore cached globals move.w k,_bk move.l b,_bb moveq #0,d0 ; return "no error"return: movem.l (sp)+,savregs unlk a5 rts
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -