Skip to content
REFERENCE / ZLIB × LEAN

deflate_base.c.lean

Source snapshot · 0f1318f4ba9afa57 · Source at the matching commit ↗

Lean source with line numbers. Follow a line number to locate a statement, or an import to read its dependency.

1import ZlibF.Runtime.Alloc
2import ZlibF.Runtime.Tables
3import ZlibF.Zlib.«adler32.c»
4import ZlibF.Zlib.«zutil.c»
5import ZlibF.Zlib.«trees.c»
6import ZlibF.Zlib.«crc32.c»
7
8/-!
9# deflate.c, part 1: shared definitions, hash macros, `slide_hash`, `read_buf`, `fill_window`, `flush_pending`
10
11Source: `deflate.c` and `deflate.h` of the verified source (no patch touches them), default x86_64 Linux build
12(LP64; `GZIP` defined; `LIT_MEM`, `FASTEST`, `UNALIGNED_OK`, `ZLIB_DEBUG`, `Z_SOLO` undefined). The other parts of
13the file are `deflate_strategies.c.lean` (`longest_match`, `deflate_stored`, `deflate_fast`, `deflate_slow`,
14`deflate_rle`, `deflate_huff`) and `deflate.c.lean` (the public functions).
15
16Decisions (each is also marked where it is used):
17
18* A `deflate_state *` is a `DeflateStatePtr`, a `z_streamp` a `ZStreamPtr`. `s->f` is `rd s (·.f)`, and `s->f = v` is
19  `wr s (fun d => { d with f := v })`: a load of the record, a record update and a store, so every access faults on a
20  null, dangling or wrong-kind pointer.
21* `ZALLOC`/`ZFREE` call through `strm->zalloc`/`zfree`. Only the default `zcalloc`/`zcfree` (`FnPtr.fn "zcalloc"`,
22  `"zcfree"`, installed by `deflateInit2_`) are modelled; any other function is `ub "custom allocator not modelled"`.
23  `Posf *` blocks (`prev`, `head`) are blocks of the `words` table, so `ZALLOC(strm, n, sizeof(Pos))` is `allocW`
24  of the number of 16-bit words in the `n * 2` bytes (the product is taken in `unsigned`, as in `zcalloc`)
25  and `zmemzero` of such a block counts words.
26* Signed `int` and `long` arithmetic is checked (`iadd`, `isub`, `ishl`, ...: overflow and invalid shifts are
27  `Fault.ub`); unsigned arithmetic wraps.
28* An `unsigned char *` or `char *` is a `BPtr`; `p + n` is `Ptr.add`, `*p` is `Ptr.load`, `p[i]` is `index8`.
29* Output parameters (`unsigned *pending`, `uInt *dictLength`, `z_size_t *destLen`) are modelled in the files that
30  use them as an input value and a result.
31* The control tags of loops with `break` or `return` are fields of the loop state.
32-/
33
34namespace Zlib.Deflate
35open C
36open Zlib.Trees («_tr_init» «_tr_flush_bits» «_tr_flush_block» «_tr_stored_block» «_tr_align»)
37open Zlib.Crc32 (crc32 crc32_z)
38
39/-! ## Constants of `deflate.c` and `deflate.h` -/
40
41def MIN_MATCH_u : UInt32 := 3          -- MIN_MATCH
42def MAX_MATCH_u : UInt32 := 258        -- MAX_MATCH
43def MIN_LOOKAHEAD_u : UInt32 := 262    -- MIN_LOOKAHEAD = MAX_MATCH+MIN_MATCH+1
44def WIN_INIT_u : UInt64 := 258         -- WIN_INIT = MAX_MATCH
45def MAX_STORED : UInt32 := 65535
46def TOO_FAR : UInt32 := 4096
47def sizeof_z_stream : Int32 := 112     -- sizeof(z_stream), LP64
48
49/-- `block_state` (`enum`, so `unsigned`). -/
50abbrev block_state := UInt32
51def need_more : block_state := 0
52def block_done : block_state := 1
53def finish_started : block_state := 2
54def finish_done : block_state := 3
55
56/-- Which function `config.func` points to (D-6: function pointers to the local compressors are an enum). -/
57inductive CompressFunc where
58  | stored | fast | slow
59  deriving DecidableEq, Inhabited
60
61/-- `struct config_s` -/
62structure Config where
63  good_length : UInt16
64  max_lazy : UInt16
65  nice_length : UInt16
66  max_chain : UInt16
67  func : CompressFunc
68  deriving Inhabited
69
70/-- `local const config configuration_table[10]` -/
71def configuration_table : Array Config := #[
72  -- level 0
73  ⟨0, 0, 0, 0, .stored⟩,
74  -- level 1
75  ⟨4, 4, 8, 4, .fast⟩,
76  -- level 2
77  ⟨4, 5, 16, 8, .fast⟩,
78  -- level 3
79  ⟨4, 6, 32, 32, .fast⟩,
80  -- level 4
81  ⟨4, 4, 16, 16, .slow⟩,
82  -- level 5
83  ⟨8, 16, 32, 32, .slow⟩,
84  -- level 6
85  ⟨8, 16, 128, 128, .slow⟩,
86  -- level 7
87  ⟨8, 32, 128, 256, .slow⟩,
88  -- level 8
89  ⟨32, 128, 258, 1024, .slow⟩,
90  -- level 9
91  ⟨32, 258, 258, 4096, .slow⟩]
92
93/-- `configuration_table[level]`: an index outside `0..9` is undefined. -/
94def config_at (level : Int32) : M Config :=
95  if 0 ≤ level.toInt ∧ level.toInt < 10 then pure configuration_table[level.toInt.toNat]!
96  else ub "configuration_table index out of range"
97
98/-! ## Checked signed arithmetic and shifts -/
99
100def chk32 (v : Int) : M Int32 :=
101  if -2147483648 ≤ v ∧ v ≤ 2147483647 then pure (Int32.ofInt v) else ub "signed int overflow"
102def chk64 (v : Int) : M Int64 :=
103  if -9223372036854775808 ≤ v ∧ v ≤ 9223372036854775807 then pure (Int64.ofInt v) else ub "signed long overflow"
104def iadd (a b : Int32) : M Int32 := chk32 (a.toInt + b.toInt)
105def isub (a b : Int32) : M Int32 := chk32 (a.toInt - b.toInt)
106def ineg (a : Int32) : M Int32 := chk32 (-a.toInt)
107def ladd (a b : Int64) : M Int64 := chk64 (a.toInt + b.toInt)
108def lsub (a b : Int64) : M Int64 := chk64 (a.toInt - b.toInt)
109/-- `a << n` for `int`: the count must be in `0..31` and the result representable (`a >= 0`). -/
110def ishl (a : Int32) (n : Int) : M Int32 :=
111  if 0 ≤ n ∧ n < 32 ∧ 0 ≤ a.toInt then chk32 (a.toInt * 2 ^ n.toNat) else ub "invalid shift of an int"
112/-- `a << n` for `unsigned`: the count must be in `0..31`. -/
113def ushl (a : UInt32) (n : UInt32) : M UInt32 :=
114  if n < 32 then pure (a <<< n) else ub "invalid shift of an unsigned"
115
116/-! ## Field access -/
117
118/-- `s->f` (read). -/
119@[inline] def rd {α : Type} (s : DeflateStatePtr) (f : DeflateState → α) : M α := do
120  return f (← ldDeflateState s)
121/-- `s->f = v` and the like (a record update). -/
122@[inline] def wr (s : DeflateStatePtr) (f : DeflateState → DeflateState) : M Unit := do
123  let d ← ldDeflateState s
124  stDeflateState s (f d)
125/-- `strm->f` (read). -/
126@[inline] def zrd {α : Type} (strm : ZStreamPtr) (f : ZStream → α) : M α := do
127  return f (← ldZStream strm)
128/-- `strm->f = v` and the like. -/
129@[inline] def zwr (strm : ZStreamPtr) (f : ZStream → ZStream) : M Unit := do
130  let z ← ldZStream strm
131  stZStream strm (f z)
132
133/-- `p + n` for a pointer and a nonnegative count. -/
134@[inline] def padd {R T : Type} [Space Heap R T] (p : Ptr R) (n : Nat) : M (Ptr R) := Ptr.add p (n : Int)
135/-- `p - n`. -/
136@[inline] def psub {R T : Type} [Space Heap R T] (p : Ptr R) (n : Nat) : M (Ptr R) := Ptr.add p (-(n : Int))
137/-- `p[i] = v` for a byte pointer and an index. -/
138@[inline] def store_at (p : BPtr) (i : Nat) (v : UInt8) : M Unit := do
139  store8 (← padd p i) v
140
141/-- `ZALLOC`/`ZFREE` of the default allocator only. -/
142def zalloc_default (strm : ZStreamPtr) : M Unit := do
143  let z ← ldZStream strm
144  if z.zalloc != FnPtr.fn "zcalloc" then ub "custom allocator not modelled"
145def zfree_default (strm : ZStreamPtr) : M Unit := do
146  let z ← ldZStream strm
147  if z.zfree != FnPtr.fn "zcfree" then ub "custom allocator not modelled"
148
149/-- `ZALLOC(strm, items, size)` for a byte block (`zcalloc`: `malloc(items * size)`, product in `unsigned`). -/
150def ZALLOC_bytes (strm : ZStreamPtr) (items size : UInt32) : M BPtr := do
151  zalloc_default strm
152  let z ← ldZStream strm
153  Zlib.Zutil.zcalloc z.«opaque» items size
154/-- `ZALLOC(strm, items, sizeof(Pos))` for a `Posf *` block (a block of 16-bit words). -/
155def ZALLOC_words (strm : ZStreamPtr) (items : UInt32) : M WPtr := do
156  zalloc_default strm
157  -- zcalloc: malloc(items * size) with the product in `unsigned`; the block of `Pos` has that many bytes / 2 words
158  let bytes : UInt32 := items * 2
159  allocW (bytes.toNat / 2)
160/-- `ZFREE(strm, addr)` of a byte block. -/
161def ZFREE_bytes (strm : ZStreamPtr) (p : BPtr) : M Unit := do
162  zfree_default strm
163  freeB p
164/-- `ZFREE(strm, addr)` of a block of words. -/
165def ZFREE_words (strm : ZStreamPtr) (p : WPtr) : M Unit := do
166  zfree_default strm
167  freeW p
168
169/-- `ERR_MSG(err)` -/
170def ERR_MSG (err : Int32) : M BPtr := Zlib.Zutil.zError err
171
172/-! ## Macros of `deflate.c` and `deflate.h` -/
173
174/-- `put_byte(s, c)`: `{s->pending_buf[s->pending++] = (Bytef)(c);}` (no capacity test, I-1). -/
175def put_byte (s : DeflateStatePtr) (c : UInt8) : M Unit := do
176  let d ← ldDeflateState s
177  store_at d.pending_buf d.pending.toNat c
178  stDeflateState s { d with pending := d.pending + 1 }
179
180/-- `UPDATE_HASH(s, s->ins_h, c)`: `s->ins_h = ((s->ins_h << s->hash_shift) ^ (c)) & s->hash_mask` (`c` is an
181`int` made of a byte). -/
182def UPDATE_HASH (s : DeflateStatePtr) (c : UInt8) : M Unit := do
183  let d ← ldDeflateState s
184  let sh ← ushl d.ins_h d.hash_shift
185  stDeflateState s { d with ins_h := (sh ^^^ c.toUInt32) &&& d.hash_mask }
186
187/-- `INSERT_STRING(s, str, match_head)`: returns the new `match_head`.
188`(UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]),
189  match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], s->head[s->ins_h] = (Pos)(str))` -/
190def INSERT_STRING (s : DeflateStatePtr) (str : UInt32) : M UInt32 := do
191  let d ← ldDeflateState s
192  let c ← index8 d.window (str + (MIN_MATCH_u - 1)).toNat
193  UPDATE_HASH s c
194  let d ← ldDeflateState s
195  let v ← Ptr.index d.head d.ins_h.toNat
196  Ptr.store (← padd d.prev (str &&& d.w_mask).toNat) v
197  Ptr.store (← padd d.head d.ins_h.toNat) str.toUInt16
198  return v.toUInt32
199
200/-- `CLEAR_HASH(s)`: `s->head[s->hash_size - 1] = NIL; zmemzero(s->head, (unsigned)(s->hash_size - 1)*sizeof(*s->head));
201s->slid = 0;` (the `memset` of `2 * (hash_size - 1)` bytes is `hash_size - 1` words). -/
202def CLEAR_HASH (s : DeflateStatePtr) : M Unit := do
203  let d ← ldDeflateState s
204  Ptr.store (← padd d.head (d.hash_size - 1).toNat) (0 : UInt16)
205  Ptr.fill d.head (0 : UInt16) (d.hash_size - 1).toNat
206  wr s (fun d => { d with slid := 0 })
207
208/-- `d_code(dist)`: `((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])` (`dist` is a `ush`). -/
209def d_code (dist : UInt16) : M UInt8 :=
210  if dist.toNat < 256 then index8 (.ref BRef.st_dist_code 0) dist.toNat
211  else index8 (.ref BRef.st_dist_code 0) (256 + (dist >>> 7).toNat)
212
213/-- `s->tree[i].Freq++` for the tree array `r` (`ush`, wraps). -/
214def freq_inc (r : CtDataRef) (i : Nat) : M Unit := do
215  let p : CtDataPtr := .ref r 0
216  let q ← padd p i
217  let e ← Ptr.load q
218  Ptr.store q { e with fc := e.fc + 1 }
219
220/-- `_tr_tally_lit(s, c, flush)` (`flush` is the result). -/
221def tally_lit (s : DeflateStatePtr) (c : UInt8) : M Bool := do
222  let cc := c   -- uch cc = (c);
223  let d ← ldDeflateState s
224  -- s->sym_buf[s->sym_next++] = 0; (twice) = cc;
225  store_at d.sym_buf d.sym_next.toNat 0
226  store_at d.sym_buf (d.sym_next + 1).toNat 0
227  store_at d.sym_buf (d.sym_next + 2).toNat cc
228  stDeflateState s { d with sym_next := d.sym_next + 3 }
229  -- s->dyn_ltree[cc].Freq++;
230  match s with
231  | none => ub "null deflate_state"
232  | some (.tab id) =>
233    freq_inc (.dstate_dyn_ltree id) cc.toNat
234    -- flush = (s->sym_next == s->sym_end);
235    let d ← ldDeflateState s
236    return d.sym_next == d.sym_end
237
238/-- `_tr_tally_dist(s, distance, length, flush)` (the arguments are `unsigned` expressions). -/
239def tally_dist (s : DeflateStatePtr) (distance length : UInt32) : M Bool := do
240  let len : UInt8 := length.toUInt8            -- uch len = (uch)(length);
241  let dist : UInt16 := distance.toUInt16       -- ush dist = (ush)(distance);
242  let d ← ldDeflateState s
243  store_at d.sym_buf d.sym_next.toNat dist.toUInt8
244  store_at d.sym_buf (d.sym_next + 1).toNat (dist >>> 8).toUInt8
245  store_at d.sym_buf (d.sym_next + 2).toNat len
246  stDeflateState s { d with sym_next := d.sym_next + 3 }
247  let dist : UInt16 := dist - 1                -- dist--;
248  match s with
249  | none => ub "null deflate_state"
250  | some (.tab id) =>
251    -- s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++;
252    let lc ← index8 (.ref BRef.st_length_code 0) len.toNat
253    freq_inc (.dstate_dyn_ltree id) (lc.toNat + 256 + 1)
254    -- s->dyn_dtree[d_code(dist)].Freq++;
255    let dc ← d_code dist
256    freq_inc (.dstate_dyn_dtree id) dc.toNat
257    let d ← ldDeflateState s
258    return d.sym_next == d.sym_end
259
260/-! ## `slide_hash` -/
261
262/-- `local void slide_hash(deflate_state *s)` -/
263def slide_hash (s : DeflateStatePtr) : M Unit := do
264  let d ← ldDeflateState s
265  let wsize : UInt32 := d.w_size                 -- uInt wsize = s->w_size;
266  let n : UInt32 := d.hash_size                  -- n = s->hash_size;
267  let p : WPtr ← padd d.head n.toNat             -- p = &s->head[n];
268  -- do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); } while (--n);
269  let (_, _) ← cdoWhile
270    (fun (n, p) => do
271      let p ← psub p 1
272      let m : UInt32 := (← Ptr.load p).toUInt32
273      Ptr.store p (if m ≥ wsize then (m - wsize).toUInt16 else (0 : UInt16))
274      pure (n, p))
275    (fun (n, p) => let n := n - 1; pure (n != 0, (n, p)))
276    (n, p)
277  -- #ifndef FASTEST
278  let n : UInt32 := wsize                        -- n = wsize;
279  let p : WPtr ← padd d.prev n.toNat             -- p = &s->prev[n];
280  let (_, _) ← cdoWhile
281    (fun (n, p) => do
282      let p ← psub p 1
283      let m : UInt32 := (← Ptr.load p).toUInt32
284      Ptr.store p (if m ≥ wsize then (m - wsize).toUInt16 else (0 : UInt16))
285      pure (n, p))
286    (fun (n, p) => let n := n - 1; pure (n != 0, (n, p)))
287    (n, p)
288  -- s->slid = 1;
289  wr s (fun d => { d with slid := 1 })
290
291/-! ## `read_buf` and `fill_window` -/
292
293/-- `local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size)` -/
294def read_buf (strm : ZStreamPtr) (buf : BPtr) (size : UInt32) : M UInt32 := do
295  let mut len ← zrd strm (·.avail_in)            -- unsigned len = strm->avail_in;
296  if len > size then len := size
297  if len == 0 then return 0
298  -- strm->avail_in -= len;
299  zwr strm (fun z => { z with avail_in := z.avail_in - len })
300  -- zmemcpy(buf, strm->next_in, len);
301  memcpyB buf (← zrd strm (·.next_in)) len.toNat
302  let sp ← castDeflateState (← zrd strm (·.state))
303  let wrap ← rd sp (·.wrap)
304  if wrap == 1 then
305    -- strm->adler = adler32(strm->adler, buf, len);
306    let a ← zrd strm (·.adler)
307    let r ← Zlib.Adler32.adler32 a buf len
308    zwr strm (fun z => { z with adler := r })
309  else if wrap == 2 then
310    -- strm->adler = crc32(strm->adler, buf, len);
311    let a ← zrd strm (·.adler)
312    let r ← crc32 a buf len
313    zwr strm (fun z => { z with adler := r })
314  -- strm->next_in += len; strm->total_in += len;
315  let ni ← padd (← zrd strm (·.next_in)) len.toNat
316  zwr strm (fun z => { z with next_in := ni, total_in := z.total_in + len.toUInt64 })
317  return len
318
319/-- `local void fill_window(deflate_state *s)`.
320The loop `do { ... } while (cond)` has two `break`s; the state of the outer loop is the flag `brk`. The
321`if (sizeof(int) <= 2)` block is dead (`sizeof(int)` is 4). -/
322def fill_window (s : DeflateStatePtr) : M Unit := do
323  let wsize ← rd s (·.w_size)                    -- uInt wsize = s->w_size;
324  let _ ← cdoWhile
325    (fun (_ : Bool) => do
326      let d ← ldDeflateState s
327      -- more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
328      let mut more : UInt32 := (d.window_size - d.lookahead.toUInt64 - d.strstart.toUInt64).toUInt32
329      -- if (s->strstart >= wsize + MAX_DIST(s)) { ... }   (MAX_DIST(s) = w_size - MIN_LOOKAHEAD)
330      if d.strstart ≥ wsize + (d.w_size - MIN_LOOKAHEAD_u) then
331        -- zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
332        memcpyB d.window (← padd d.window wsize.toNat) (wsize - more).toNat
333        wr s (fun d => { d with match_start := d.match_start - wsize }) -- s->match_start -= wsize;
334        wr s (fun d => { d with strstart := d.strstart - wsize })       -- s->strstart -= wsize;
335        let block_start ← lsub (← rd s (·.block_start)) wsize.toUInt64.toInt64
336        wr s (fun d => { d with block_start })                         -- s->block_start -= (long) wsize;
337        -- if (s->insert > s->strstart) s->insert = s->strstart;
338        wr s (fun d => { d with insert := if d.insert > d.strstart then d.strstart else d.insert })
339        slide_hash s
340        more := more + wsize                                             -- more += wsize;
341      -- if (s->strm->avail_in == 0) break;
342      let strm ← rd s (·.strm)
343      if (← zrd strm (·.avail_in)) == 0 then return true
344      -- n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
345      let d ← ldDeflateState s
346      let dst ← padd (← padd d.window d.strstart.toNat) d.lookahead.toNat
347      let n ← read_buf strm dst more
348      wr s (fun d => { d with lookahead := d.lookahead + n })            -- s->lookahead += n;
349      -- if (s->lookahead + s->insert >= MIN_MATCH) { ... }
350      let d ← ldDeflateState s
351      if d.lookahead + d.insert ≥ MIN_MATCH_u then
352        let str : UInt32 := d.strstart - d.insert                    -- uInt str = s->strstart - s->insert;
353        -- s->ins_h = s->window[str];
354        let c0 ← index8 d.window str.toNat
355        wr s (fun d => { d with ins_h := c0.toUInt32 })
356        -- UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
357        UPDATE_HASH s (← index8 d.window (str + 1).toNat)
358        -- while (s->insert) { ... }
359        let (_, _) ← cwhile
360          (fun (str, brk) => do
361            let ins ← rd s (·.insert)
362            pure (ins != 0 && !brk, (str, brk)))
363          (fun (str, brk) => do
364            let d ← ldDeflateState s
365            -- UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
366            UPDATE_HASH s (← index8 d.window (str + (MIN_MATCH_u - 1)).toNat)
367            let d ← ldDeflateState s
368            -- s->prev[str & s->w_mask] = s->head[s->ins_h];
369            let v ← Ptr.index d.head d.ins_h.toNat
370            Ptr.store (← padd d.prev (str &&& d.w_mask).toNat) v
371            -- s->head[s->ins_h] = (Pos)str;
372            Ptr.store (← padd d.head d.ins_h.toNat) str.toUInt16
373            -- str++; s->insert--;
374            let str := str + 1
375            wr s (fun d => { d with insert := d.insert - 1 })
376            -- if (s->lookahead + s->insert < MIN_MATCH) break;
377            let d ← ldDeflateState s
378            pure (str, d.lookahead + d.insert < MIN_MATCH_u))
379          (str, false)
380      pure false)
381    (fun brk => do
382      if brk then return (false, brk)
383      -- while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0)
384      let d ← ldDeflateState s
385      if d.lookahead < MIN_LOOKAHEAD_u then
386        return ((← zrd d.strm (·.avail_in)) != 0, brk)
387      return (false, brk))
388    false
389  -- if (s->high_water < s->window_size) { ... }
390  let d ← ldDeflateState s
391  if d.high_water < d.window_size then
392    let curr : UInt64 := d.strstart.toUInt64 + d.lookahead.toUInt64   -- ulg curr = s->strstart + (ulg)(s->lookahead);
393    if d.high_water < curr then
394      -- init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT;
395      let mut init : UInt64 := d.window_size - curr
396      if init > WIN_INIT_u then init := WIN_INIT_u
397      -- zmemzero(s->window + curr, (unsigned)init);
398      memsetB (← padd d.window curr.toNat) 0 init.toUInt32.toNat
399      wr s (fun d => { d with high_water := curr + init })              -- s->high_water = curr + init;
400    else if d.high_water < curr + WIN_INIT_u then
401      -- init = (ulg)curr + WIN_INIT - s->high_water;
402      let mut init : UInt64 := curr + WIN_INIT_u - d.high_water
403      -- if (init > s->window_size - s->high_water) init = s->window_size - s->high_water;
404      if init > d.window_size - d.high_water then init := d.window_size - d.high_water
405      -- zmemzero(s->window + s->high_water, (unsigned)init);
406      memsetB (← padd d.window d.high_water.toNat) 0 init.toUInt32.toNat
407      wr s (fun d => { d with high_water := d.high_water + init })      -- s->high_water += init;
408
409/-! ## `putShortMSB`, `flush_pending` -/
410
411/-- `local void putShortMSB(deflate_state *s, uInt b)` -/
412def putShortMSB (s : DeflateStatePtr) (b : UInt32) : M Unit := do
413  put_byte s (b >>> 8).toUInt8        -- put_byte(s, (Byte)(b >> 8));
414  put_byte s (b &&& 0xff).toUInt8     -- put_byte(s, (Byte)(b & 0xff));
415
416/-- `local void flush_pending(z_streamp strm)` -/
417def flush_pending (strm : ZStreamPtr) : M Unit := do
418  let s ← castDeflateState (← zrd strm (·.state))       -- deflate_state *s = strm->state;
419  _tr_flush_bits s                                       -- _tr_flush_bits(s);
420  let z ← ldZStream strm
421  let d ← ldDeflateState s
422  -- len = s->pending > strm->avail_out ? strm->avail_out : (unsigned)s->pending;
423  let len : UInt32 := if d.pending > z.avail_out.toUInt64 then z.avail_out else d.pending.toUInt32
424  if len == 0 then return                                -- if (len == 0) return;
425  -- zmemcpy(strm->next_out, s->pending_out, len);
426  memcpyB z.next_out d.pending_out len.toNat
427  -- strm->next_out += len; s->pending_out += len;
428  let no ← padd z.next_out len.toNat
429  let po ← padd d.pending_out len.toNat
430  -- strm->total_out += len; strm->avail_out -= len;
431  stZStream strm { z with next_out := no, total_out := z.total_out + len.toUInt64, avail_out := z.avail_out - len }
432  -- s->pending -= len;
433  let pend := d.pending - len.toUInt64
434  stDeflateState s { d with pending_out := po, pending := pend }
435  -- if (s->pending == 0) s->pending_out = s->pending_buf;
436  if pend == 0 then wr s (fun d => { d with pending_out := d.pending_buf })
437
438/-- `FLUSH_BLOCK_ONLY(s, last)` -/
439def FLUSH_BLOCK_ONLY (s : DeflateStatePtr) (last : Int32) : M Unit := do
440  let d ← ldDeflateState s
441  -- (s->block_start >= 0L ? (charf *)&s->window[(unsigned)s->block_start] : (charf *)Z_NULL)
442  let buf ← if d.block_start ≥ 0 then padd d.window d.block_start.toUInt64.toUInt32.toNat else pure (Ptr.null : BPtr)
443  -- (ulg)((long)s->strstart - s->block_start)
444  let n ← lsub d.strstart.toUInt64.toInt64 d.block_start
445  «_tr_flush_block» s buf n.toUInt64 last
446  -- s->block_start = s->strstart;
447  wr s (fun d => { d with block_start := d.strstart.toUInt64.toInt64 })
448  -- flush_pending(s->strm);
449  flush_pending (← rd s (·.strm))
450
451/-- `FLUSH_BLOCK(s, last)`: the `return`s of the macro are `some state`; `none` falls through. -/
452def FLUSH_BLOCK (s : DeflateStatePtr) (last : Int32) : M (Option block_state) := do
453  FLUSH_BLOCK_ONLY s last
454  let d ← ldDeflateState s
455  if (← zrd d.strm (·.avail_out)) == 0 then
456    if last == 0 then return some need_more                 -- if (!(last)) return need_more;
457    if d.pending != 0 || d.wrap != 0 then return some finish_started
458  return none
459
460end Zlib.Deflate
ZLIB × LEAN

Global contents

READING NOWdeflate_base.c.lean