File: zlib.lisp

package info (click to toggle)
acl2 8.6%2Bdfsg-2
  • links: PTS
  • area: main
  • in suites: trixie
  • size: 1,111,420 kB
  • sloc: lisp: 17,818,294; java: 125,359; python: 28,122; javascript: 23,458; cpp: 18,851; ansic: 11,569; perl: 7,678; xml: 5,591; sh: 3,976; makefile: 3,833; ruby: 2,633; yacc: 1,126; ml: 763; awk: 295; csh: 233; lex: 197; php: 178; tcl: 49; asm: 23; haskell: 17
file content (144 lines) | stat: -rw-r--r-- 5,895 bytes parent folder | download | duplicates (3)
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
(in-package 3bz)

(defstruct (zlib-state (:conc-name zs-)
                       (:include deflate-state))
  (zlib-state :header)
  (compression-method nil)
  (window-size 0)
  (dict-id nil)
  (compression-level :default)
  ;; checksum state
  (s1 1 :type (unsigned-byte 16))
  (s2 0 :type (unsigned-byte 16)))

(defun check-zlib-header (cmf flg &key (errorp t))
  (let* ((cm (ldb (byte 4 0) cmf))
         (cinfo (ldb (byte 4 4) cmf))
         (check (zerop (mod (+ (* cmf 256) flg) 31)))
         (dict (logbitp 5 flg))
         (level (ldb (byte 2 6) flg)))
    (when (not check)
      (when errorp
        (error "invalid zlib header checksum")))
    (if (= cm 8)
        (setf cm :deflate)
        (progn
          (when errorp
            (error "invalid zlib compression type"))
          (setf check nil)))
    (when (> cinfo 7)
      (when errorp
        (error "invalid window size in zlib header"))
      (setf check nil))
    (when dict
      (when errorp
        (error "preset dictionary not supported yet"))
      (setf check nil))
    (values check cm cinfo dict level)))

(defun decompress-zlib (read-context state)
  (check-type state zlib-state)
  ;; fixme: avoid duplication with these from deflate
  (with-reader-contexts (read-context)
    (with-accessors ((input-underrun zs-input-underrun)
                     (zlib-state zs-zlib-state)
                     (partial-bits zs-partial-bits)
                     (bits-remaining zs-bits-remaining)
                     (finished zs-finished)
                     (window-size zs-window-size)
                     (compression-level zs-compression-level)
                     (dict-id zs-dict-id)
                     (compression-method zs-compression-method)
                     (output-offset zs-output-offset)
                     (output-overflow zs-output-overflow))
        state
      (labels ((%fill-bits32 (n)
                 (multiple-value-bind (input octets)
                     (word32)
                   (declare (type (mod 5) octets))
                   (setf partial-bits
                         (logior
                          (ash (ldb (byte 32 0) input)
                               (min 32 bits-remaining))
                          partial-bits))
                   (incf bits-remaining (* 8 octets))
                   (>= bits-remaining n)))
               (%bits (n)
                 (prog1 (ldb (byte n 0) partial-bits)
                   (setf partial-bits (ash partial-bits (- n)))
                   (decf bits-remaining n)))
               (byte-align ()
                 (let ((r (mod bits-remaining 8)))
                   (unless (zerop r)
                     (setf partial-bits (ash partial-bits (- r)))
                     (decf bits-remaining r))))
               ;; these are called from 2 places to allow finishing in
               ;; single call, while trying to minimize conditionals
               ;; in hot path when working with input/output in chunks
               (dictid ()
                 (error "preset dictionary not supported yet"))
               (adler ()
                 (when (and (< bits-remaining 32)
                            (not (%fill-bits32 32)))
                   (setf input-underrun t)
                   (return-from decompress-zlib
                     output-offset))
                 (let ((adler32 (logior (ash (%bits 8) 24)
                                        (ash (%bits 8) 16)
                                        (ash (%bits 8) 8)
                                        (ash (%bits 8) 0)))
                       (calculated (logior (zs-s1 state)
                                           (ash (zs-s2 state) 16))))
                   (declare (optimize (speed 1)))
                   ;;(format t "checksum = ~8,'0x~%" adler32)
                   ;;(format t "calculated = ~8,'0x~%" calculated)
                   (assert (= adler32 calculated))
                   (setf finished t)))
               (update-checksum ()
                 (declare (optimize speed))
                 (setf (values (zs-s1 state) (zs-s2 state))
                       (adler32 (zs-output-buffer state)
                                output-offset
                                (zs-s1 state) (zs-s2 state)))))
        (declare (inline %fill-bits32 %bits byte-align)
                 (optimize (speed 1)))
        (setf input-underrun nil)
        (when zlib-state
          (case zlib-state
            (:header
             (when (and (< bits-remaining 16)
                        (not (%fill-bits32 16)))
               (setf input-underrun t)
               (return-from decompress-zlib 0))
             (multiple-value-bind (ok cm cinfo dict level)
                 (check-zlib-header (%bits 8) (%bits 8))
               (declare (ignore ok))
               (setf compression-level
                     (aref #(:fastest :fast :default :maximum) level))
               (setf window-size (expt 2 (+ cinfo 8)))2
               (setf compression-method cm)
               (setf dict-id dict)
               (when dict
                 (setf zlib-state :header2)
                 (dictid))
               #++
               (format t "zlib header: method ~s, level ~s, window ~s, dict ~s~%"
                       compression-method compression-level window-size dict-id)))
            (:header2
             (dictid))
            (:adler
             (adler)
             (setf zlib-state nil)
             (return-from decompress-zlib output-offset)))
          (setf zlib-state nil))
        (unless zlib-state
          (decompress-deflate read-context state)
          (when (or finished output-overflow)
            (update-checksum))
          (when finished
            (byte-align)
            (setf zlib-state :adler)
            (setf finished nil)))
        (when (eql :adler zlib-state)
          (adler))
        output-offset))))