File: flate.a

package info (click to toggle)
unzip 5.40-1
  • links: PTS
  • area: non-free
  • in suites: potato
  • size: 4,120 kB
  • ctags: 5,900
  • sloc: ansic: 40,977; cpp: 3,778; makefile: 1,384; asm: 1,228; sh: 133
file content (439 lines) | stat: -rw-r--r-- 15,799 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
; 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 "Uz_Globs *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 Uz_Globs 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              ; Uz_Globs
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              ; Uz_Globs *

; 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)<<k;k+=8;}}
;   #define DUMPBITS(n) {b>>=(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)<<k;k+=8;}}
;
; 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        MACRO
nb\@:   cmp.w           \1,k            ; assert 0 < k <= 32 ... arg may be 0
        bhs.s           ne\@
        NEXTBYTE                        ; returns in d0.l
                 IFND   NO_CHECK_EOF
        cmp.w           #EOF,d0
        bne.s           nok\@
        moveq           #1,d0           ; PK_WARN?
        bra             return
                 ENDC   ; !NO_CHECK_EOF
nok\@:  lsl.l           k,d0
        or.l            d0,b
        addq.w          #8,k
        bra.s           nb\@
ne\@:   move.w          b,d1
                ENDM

DUMPBITS        MACRO
        lsr.l           \1,b            ; upper bits of \1 are ignored??
        sub.b           \1,k
                ENDM


; ******************************************************************************
; Here we go, finally:

        xdef    _inflate_codes

_inflate_codes:
        link            a5,#-4
        movem.l         savregs,-(sp)
; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18|20(a5) = bd... add 4 for REENT_G
; -2(a5) = ml, -4(a5) = md.  Here we cache some globals and args:
                IFD     REENT_G
        move.l          8(a5),G
                ELSE
;;      move.l          _G,G            ; old global pointer version
        lea             _G,G            ; G is now a global instance
                ENDC
        lea             _mask_bits,mask
        move.l          bb(G),b
        MOVINT          bk(G),k
                IFD     INT16
        moveq           #0,w            ; keep this usable as longword
                ENDC
        MOVINT          wp(G),w
        moveq           #0,e            ; keep this usable as longword too
        MOVINT          16+G_SIZE(a5),d0
        add.w           d0,d0
        move.w          (mask,d0.w),-2(a5)      ; ml = mask_bits[bl]
        MOVINT          16+INTSIZE+G_SIZE(a5),d0
        add.w           d0,d0
        move.w          (mask,d0.w),-4(a5)      ; md = mask_bits[bd]

main_loop:
        NEEDBITS        14+INTSIZE+G_SIZE(a5)   ; bl, lower word if long
        and.w           -2(a5),d1               ; ml
        mulu            #SIZEOF_HUFT,d1
        move.l          8+G_SIZE(a5),a0         ; tl
        lea             (a0,d1.l),t
        move.b          h_e(t),e
        cmp.w           #16,e
        bls.s           topdmp
intop:   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          intop
topdmp: 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
                IFGT    SIZEOF_slide-4
        lea             slide(G),a0
                ELSE
        move.l          slide(G),a0
                ENDC
        move.b          d0,(a0,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 more

lenchk: 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        14+(2*INTSIZE)+G_SIZE(a5)       ; bd, lower word if long
        and.w           -4(a5),d1                       ; md
        mulu            #SIZEOF_HUFT,d1
        move.l          12+G_SIZE(a5),a0                ; td
        lea             (a0,d1.l),t
        move.b          h_e(t),e
        cmp.w           #16,e
        bls.s           middmp
inmid:   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          inmid
middmp: 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        e

indup:   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          dadw
ddgw:     sub.w         d,e
dadw:    cmp.w          n,e
         bls.s          delen
          move.w        n,e
delen:   sub.w          e,n             ; size of sub-block to copy
                IFGT    SIZEOF_slide-4
         lea            slide(G),a0
                ELSE
         move.l         slide(G),a0
                ENDC
         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 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