; Not copyrighted by Paul Kienitz, 20 June 94. Last modified 21 Feb 96. ; ; 68000 assembly language version of inflate_codes(), for Amiga. Prototype: ; ; int inflate_codes(__GPRO__ struct huft *tl, struct huft *td, ; int bl, int bd); ; ; Where __GPRO__ expands to "struct Globals *G," if REENTRANT is defined, ; otherwise to nothing. In the latter case G is a global variable. ; ; Define the symbol FUNZIP if this is for fUnZip. It overrides REENTRANT. ; ; Define AZTEC to use the Aztec C macro version of getc() instead of the ; library getc() with FUNZIP. AZTEC is ignored if FUNZIP is not defined. ; ; Define NO_CHECK_EOF to not use the fancy paranoid version of NEEDBITS -- ; this is equivalent to removing the #define CHECK_EOF from inflate.c. ; ; Define INT16 if ints are short, otherwise it assumes ints are long. ; ; *DO NOT* define WSIZE -- this only works with the default value of 32K. IFD INT16 MOVINT MACRO move.w \1,\2 ENDM INTSIZE equ 2 ELSE ; !INT16 MOVINT MACRO move.l \1,\2 ENDM INTSIZE equ 4 ENDC IFD REENTRANT IFND FUNZIP REENT_G equ 1 ENDC ENDC ; 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 0 h_b equ 1 h_n equ 2 h_t equ 2 SIZEOF_HUFT equ 6 ; The following include file is generated from globals.h, and gives us equates ; that give the offsets in struct Globals of the fields we use, which are: ; ulg bb ; unsigned int bk, wp ; (either array of or pointer to unsigned char) slide ; For fUnZip: ; FILE *in ; For regular UnZip but not fUnZip: ; int incnt, mem_mode ; long csize ; uch *inptr ; It also defines a value SIZEOF_slide, which tells us whether the appropriate ; slide field in G (either area.Slide or redirect_pointer) is a pointer or an ; array instance. It is 4 in the former case and a large value in the latter. ; Lastly, this include will define CRYPT as 1 if appropriate. IFD FUNZIP INCLUDE "amiga/G_offs.fa" ELSE INCLUDE "amiga/G_offs.a" ENDC ; G.bb is the global buffer that holds bits from the huffman code stream, which ; we cache in the register variable b. G.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. IFD REENT_G G_SIZE equ 4 G_PUSH MACRO ; this macro passes "__G__" to functions move.l G,-(sp) ENDM ELSE xref _G ; struct Globals G_SIZE equ 0 G_PUSH MACRO ds.b 0 ; does nothing; the assembler dislikes MACRO ENDM ENDM ENDC ; REENT_G xref _mask_bits ; const ush near mask_bits[17]; IFD FUNZIP IF CRYPT xref _encrypted ; int -- boolean flag xref _update_keys ; int update_keys(__GPRO__ int) xref _decrypt_byte ; int decrypt_byte(__GPRO) ENDC ; CRYPT ELSE ; !FUNZIP xref _memflush ; int memflush(__GPRO__ uch *, ulg) xref _readbyte ; int readbyte(__GPRO) ENDC ; FUNZIP xref _getc ; int getc(FILE *) xref _flush ; if FUNZIP: int flush(__GPRO__ ulg) ; else: int flush(__GPRO__ uch *, ulg *, int) ; Here are our register variables. b equr d2 ; ulg k equr d3 ; ush <= 32 e equr d4 ; ush < 256 for most use w equr d5 ; unsigned int n equr d6 ; ush d equr d7 ; unsigned int ; We always maintain w and d as valid unsigned longs, though they may be short. t equr a2 ; struct huft * mask equr a3 ; ush * G equr a6 ; struct Globals * ; Couple other items we need: savregs reg d2-d7/a2/a3/a6 WSIZE equ $8000 ; 32k... be careful not to treat as negative! EOF equ -1 IFD FUNZIP ; This does getc(in). Aztec version is based on #define getc(fp) in stdio.h IFD AZTEC xref __filbuf GETC MACRO move.l in(G),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 ; !AZTEC GETC MACRO move.l in(G),-(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. ; FLUSH also has different forms for UnZip and fUnZip. Arg must be a longword. ; The same scratch registers are trashed. IFD FUNZIP NEXTBYTE MACRO GETC IF CRYPT tst.w _encrypted+INTSIZE-2 ; test low word if long beq.s nbe\@ MOVINT d0,-(sp) ; save thru next call G_PUSH jsr _decrypt_byte eor.w d0,G_SIZE+INTSIZE-2(sp) ; becomes arg to update_keys jsr _update_keys addq #INTSIZE+G_SIZE,sp nbe\@: IFEQ INTSIZE-2 ext.l d0 ; assert -1 <= d0 <= 255 ENDC ENDC ; !CRYPT ENDM FLUSH MACRO move.l \1,-(sp) G_PUSH jsr _flush addq #4+G_SIZE,sp ENDM ELSE ; !FUNZIP NEXTBYTE MACRO ;; subq.l #1,csize(G) ;; bge.s nbg\@ ;; moveq #EOF,d0 ;; bra.s nbe\@ nbg\@: subq.w #1,incnt+INTSIZE-2(G) ; treat as short bge.s nbs\@ G_PUSH jsr _readbyte IFNE G_SIZE addq #G_SIZE,sp ENDC bra.s nbe\@ nbs\@: moveq #0,d0 move.l inptr(G),a0 move.b (a0)+,d0 move.l a0,inptr(G) nbe\@: ENDM FLUSH MACRO MOVINT #0,-(sp) ; unshrink flag: always false move.l \1,-(sp) ; length IFGT SIZEOF_slide-4 pea slide(G) ; buffer to flush ELSE move.l slide(G),-(sp) ENDC G_PUSH tst.w mem_mode+INTSIZE-2(G) ; test lower word if long beq.s fm\@ jsr _memflush ; ignores the unshrink flag bra.s fe\@ fm\@: jsr _flush fe\@: lea 8+INTSIZE+G_SIZE(sp),sp ENDM ENDC ; ?FUNZIP ; Here are the two bit-grabbing macros, defined in their NO_CHECK_EOF form: ; ; #define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<>=(n);k-=(n);} ; ; Without NO_CHECK_EOF, NEEDBITS reads like this: ; ; {while(k<(n)){int c=NEXTBYTE;if(c==EOF)return 1;b|=((ulg)c)<= 0 if sign extended dspin: 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,w dnfl: 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 more finish: MOVINT w,wp(G) ; restore cached globals MOVINT k,bk(G) move.l b,bb(G) moveq #0,d0 ; return "no error" return: movem.l (sp)+,savregs unlk a5 rts