File: flate.a

package info (click to toggle)
unzip 6.0-16%2Bdeb8u3
  • links: PTS
  • area: main
  • in suites: jessie
  • size: 8,768 kB
  • ctags: 10,194
  • sloc: ansic: 55,133; cpp: 4,084; makefile: 2,517; asm: 1,789; cs: 1,012; sh: 119
file content (513 lines) | stat: -rw-r--r-- 19,747 bytes parent folder | download | duplicates (10)
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
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
;===========================================================================
; Copyright (c) 1990-2005 Info-ZIP.  All rights reserved.
;
; See the accompanying file LICENSE, version 2000-Apr-09 or later
; (the contents of which are also included in unzip.h) for terms of use.
; If, for some reason, all these files are missing, the Info-ZIP license
; also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
;===========================================================================
; flate.a created by Paul Kienitz, 20 June 94.  Last modified 30 Dec 2005.
;
; 68000 assembly language version of inflate_codes(), for Amiga.  Prototype:
;
;   int inflate_codes(__GPRO__ struct huft *tl, struct huft *td,
;                     unsigned bl, unsigned 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 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.
;
; Define USE_DEFLATE64 if we're supporting Deflate64 decompression.
;
; Do NOT define WSIZE; it is always 32K or 64K depending on USE_DEFLATE64.
; You also do not need to define FUNZIP or SFX, if you create t:G_offs.a
; correctly (see below).
;
; ------
;
; The following include file is generated from globals.h just before this
; is compiled, 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 unsigned char, or pointer to unsigned char) redirslide
; For regular UnZip but not fUnZip:
;       int incnt, mem_mode
;       uch *inptr
; For fUnZip:
;       FILE *in
; 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 and supply flag
; definitions for major compile options that may affect the layout of the
; globals structure and the functionality of the core decompression routines
; (currently FUNZIP, SFX, REENTRANT, DLL, NO_SLIDE_REDIR, USE_DEFLATE64).

        INCLUDE "t:G_offs.a"

; 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, or 8 if padded */
;
; The G_offs include defines offsets h_e, h_b, h_v_n, and h_v_t in this
; struct, plus SIZEOF_huft.

                IFD     REENTRANT
                 IFND   FUNZIP
REENT_G equ     1
                 ENDC
                ENDC

; These macros allow us to deal uniformly with short or long ints:

                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

; 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 unsigned 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    _flush          ; if FUNZIP:  int flush(__GPRO__ ulg)
                                ; else:  int flush(__GPRO__ uch *, ulg, int)

; Here are our register variables.

b       equr    d2              ; unsigned long
k       equr    d3              ; unsigned short <= 32
e       equr    d4              ; unsigned int, mostly used as unsigned char
w       equr    d5              ; unsigned long (was short before deflate64)
n       equr    d6              ; unsigned long (was short before deflate64)
d       equr    d7              ; unsigned int, used as unsigned short

t       equr    a2              ; struct huft *
lmask   equr    a3              ; ulg *
G       equr    a6              ; Uz_Globs *

; Couple other items we need:

savregs reg     d2-d7/a2/a3/a6
                IFD     USE_DEFLATE64
WSIZE   equ     $10000          ; 64K... be careful not to treat as short!
                ELSE
WSIZE   equ     $08000          ; 32K... be careful not to treat as negative!
                ENDC
EOF     equ     -1
INVALID equ     99

; inflate_codes() returns one of the following status codes:
;          0  OK
;          1  internal inflate error or EOF on input stream
;         the following return codes are passed through from FLUSH() errors
;          50 (PK_DISK)   "overflow of output space"
;          80 (IZ_CTRLC)  "canceled by user's request"

RET_OK  equ     0
RET_ERR 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
        xref    _getc
        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\@:
                  ENDC  ; !CRYPT
                  IFGT 4-INTSIZE
        ext.l           d0              ; assert -1 <= d0 <= 255
                  ENDC
                 ENDM

FLUSH            MACRO
        move.l          \1,-(sp)
        G_PUSH
        jsr             _flush
        addq            #4+G_SIZE,sp
                 ENDM

                ELSE    ; !FUNZIP

NEXTBYTE         MACRO
        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
                  IFGT 4-INTSIZE
        ext.l           d0            ; assert -1 <= d0 <= 255
                  ENDC
        bra.s           nbe\@
nbs\@:  moveq           #0,d0
        move.l          inptr(G),a0   ; alt vers: move.b inptr(G),d0
        move.b          (a0)+,d0      ;           addq   #1,inptr(G)
        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             redirslide(G)           ; buffer to flush
                  ELSE
        move.l          redirslide(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, which in their NO_CHECK_EOF form are:
;
;   #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((int)k<(int)(n)){\
;      int c=NEXTBYTE;if(c==EOF){\
;         if((int)k>=0)break;\
;         retval=1;goto cleanup_and_exit;}\
;      b|=((ulg)c)<<k;k+=8;}}
;
; ...where cleanup_and_exit just does "return retval;".  If
; FIX_PAST_EOB_BY_TABLEADJUST is defined, there's yet another version,
; which I don't think this is used by anybody:
;
;   {while(k<(n)){\
;      int c=NEXTBYTE;if(c==EOF){\
;         retval=1;goto cleanup_and_exit;}\
;      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                   ; arg is short
nb\@:   cmp.w           \1,k            ; assert 0 < k <= 32 ... arg may be 0
        bge.s           ne\@            ; signed compare
        NEXTBYTE                        ; returns in d0.l
                 IFND   NO_CHECK_EOF
        cmp.w           #EOF,d0
        bne.s           nok\@
        tst.w           k
        bge.s           ne\@
        moveq           #RET_ERR,d0
        bra             return
                 ENDC   ; !NO_CHECK_EOF
nok\@:  lsl.l           k,d0
        or.l            d0,b
        addq.w          #8,k
        bra.s           nb\@
ne\@:   move.l          b,d1            ; return a copy of b in d1
                ENDM

DUMPBITS        MACRO                   ; arg is byte, not short!
        lsr.l           \1,b            ; upper bits of \1 are ignored, right?
        sub.b           \1,k
                ENDM


; This is a longword version of the mask_bits constant array:
longmasks:      dc.l    $00000000,$00000001,$00000003,$00000007,$0000000F
                dc.l    $0000001F,$0000003F,$0000007F,$000000FF,$000001FF
                dc.l    $000003FF,$000007FF,$00000FFF,$00001FFF,$00003FFF
                dc.l    $00007FFF,$0000FFFF,0,0,0,0,0,0,0,0,0,0,0,0,0,0


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

        xdef    _inflate_codes

_inflate_codes:
        link            a5,#-8
        movem.l         savregs,-(sp)
; 8(a5) = tl, 12(a5) = td, 16(a5) = bl, 18|20(a5) = bd... add 4 for REENT_G
; -4(a5) = ml, -8(a5) = md, both unsigned long.
; Here we cache some globals and args:
                IFD     REENT_G
        move.l          8(a5),G
                ELSE
        lea             _G,G            ; G is now a global instance
                ENDC
        lea             longmasks,lmask
        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
        asl.w           #2,d0
        move.l          (lmask,d0.w),-4(a5)     ; ml = mask_bits[bl]
        MOVINT          16+INTSIZE+G_SIZE(a5),d0
        asl.w           #2,d0
        move.l          (lmask,d0.w),-8(a5)     ; md = mask_bits[bd]

        xdef newtop
        xdef nonlit
        xdef distop
        xdef docopy
        xdef nonleng
        xdef tailgo
        xdef finish
        xdef disbrk
main_loop:
        NEEDBITS        14+INTSIZE+G_SIZE(a5)   ; (unsigned) bl
        and.l           -4(a5),d1               ; ml
                IFNE SIZEOF_huft-8
        mulu            #SIZEOF_huft,d1
                ELSE
        asl.l           #3,d1
                ENDC
        move.l          8+G_SIZE(a5),t          ; tl
        add.l           d1,t
newtop:  move.b         h_b(t),d0
         DUMPBITS       d0
         move.b         h_e(t),e
         cmp.b          #32,e                   ; is it a literal?
         bne            nonlit                  ; no
          move.w        h_v_n(t),d0             ; yes
                IFGT SIZEOF_slide-4
          lea           redirslide(G),a0
                ELSE
          move.l        redirslide(G),a0
                ENDC
          move.b        d0,(a0,w.l)             ; stick in the decoded byte
          addq.l        #1,w
          cmp.l         #WSIZE,w
          blo           main_loop
           FLUSH        w
           ext.l        d0                      ; does a test as it casts long
           bne          return
           moveq        #0,w
           bra          main_loop               ; break (newtop loop)

nonlit:  cmp.b          #31,e                   ; is it a length?
         beq            finish                  ; no, it's the end marker
         bhi            nonleng                 ; no, it's something else
          NEEDBITS      e                       ; yes: a duplicate string
          move.w        e,d0
          asl.w         #2,d0
          and.l         (lmask,d0.w),d1
          moveq         #0,n                    ; cast h_v_n(t) to long
          move.w        h_v_n(t),n
          add.l         d1,n                    ; length of block to copy
          DUMPBITS      e
          NEEDBITS      14+(2*INTSIZE)+G_SIZE(a5)   ; bd, lower word if long
          and.l         -8(a5),d1                   ; md
                IFNE SIZEOF_huft-8
          mulu          #SIZEOF_huft,d1
                ELSE
          asl.l         #3,d1
                ENDC
          move.l        12+G_SIZE(a5),t                 ; td
          add.l         d1,t
distop:    move.b       h_b(t),d0
           DUMPBITS     d0
           move.b       h_e(t),e
           cmp.b        #32,e                   ; is it a literal?
           blo.s        disbrk                  ; then stop doing this
            cmp.b       #INVALID,e              ; is it bogus?
            bne.s       disgo
             moveq      #RET_ERR,d0             ; then fail
             bra        return
disgo:      and.w       #$001F,e
            NEEDBITS    e
            move.w      e,d0
            asl.w       #2,d0
            and.l       (lmask,d0.w),d1
                IFNE SIZEOF_huft-8
            mulu        #SIZEOF_huft,d1
                ELSE
            asl.l       #3,d1
                ENDC
            move.l      h_v_t(t),t
            add.l       d1,t
            bra         distop
disbrk:   NEEDBITS      e
          move.l        e,d0
          asl.w         #2,d0
          and.l         (lmask,d0.w),d1
          move.l        w,d
          move.w        h_v_n(t),d0     ; assert top word of d0 is zero
          sub.l         d0,d
          sub.l         d1,d            ; distance back to copy the block
          DUMPBITS      e

docopy:    move.l       #WSIZE,e        ; copy the duplicated string
           and.l        #WSIZE-1,d      ; ...but first check if the length
           cmp.l        d,w             ; will overflow the window...
           blo.s        ddgw
            sub.l       w,e
           bra.s        dadw
ddgw:       sub.l       d,e
dadw:      cmp.l        #$08000,e       ; also, only copy <= 32K, so we can
           bls.s        dnox            ; use a dbra loop to do it
            move.l      #$08000,e
dnox:      cmp.l        n,e
           bls.s        delen
            move.l      n,e
delen:     sub.l        e,n             ; size of sub-block to copy in this pass
                IFGT    SIZEOF_slide-4
           lea          redirslide(G),a0
                ELSE
           move.l       redirslide(G),a0
                ENDC
           move.l       a0,a1
           add.l        w,a0
           add.l        d,a1
; Now at this point we could do tests to see if we should use an optimized
; large block copying method such as movem's, but since (a) such methods require
; the source and destination to be compatibly aligned -- and odd bytes at each
; end have to be handled separately, (b) it's only worth checking for if the
; block is pretty large, and (c) most strings are only a few bytes long, we're
; just not going to bother.  Therefore we check above to make sure we move at
; most 32K in one sub-block, so a dbra loop can handle it.
dshort:    move.l       e,d0
           subq         #1,d0           ; assert >= 0
dspin:      move.b      (a1)+,(a0)+
            dbra        d0,dspin
           add.l        e,w
           add.l        e,d
           cmp.l        #WSIZE,w
           blo.s        dnfl
            FLUSH       w
            ext.l       d0              ; does a test as it casts to long
            bne         return
            moveq       #0,w
dnfl:      tst.l        n               ; need to do more sub-blocks?
           bne          docopy          ; yes
          moveq         #0,e            ; restore zeroness in upper bytes of e
          bra           main_loop       ; break (newtop loop)

nonleng: cmp.w          #INVALID,e      ; bottom of newtop loop -- misc. code
         bne.s          tailgo          ; invalid code?
          moveq         #RET_ERR,d0     ; then fail
          bra           return
tailgo:  and.w          #$001F,e
         NEEDBITS       e
         move.w         e,d0
         asl.w          #2,d0
         and.l          (lmask,d0.w),d1
                IFNE SIZEOF_huft-8
         mulu           #SIZEOF_huft,d1
                ELSE
         asl.l          #3,d1
                ENDC
         move.l         h_v_t(t),t
         add.l          d1,t
         bra            newtop

finish: MOVINT          w,wp(G)         ; done: restore cached globals
        MOVINT          k,bk(G)
        move.l          b,bb(G)
        moveq           #RET_OK,d0      ; return "no error"
return: movem.l         (sp)+,savregs
        unlk            a5
        rts