跳到正文
参考文档 / ZLIB × LEAN

inflate.c.lean

此页源文件快照 · 6b06baf89b997a81 · 对应提交的原文 ↗

本页保留 Lean 源码及行号。点击行号可定位语句,点击 import 中的模块名可查看依赖。

1import ZlibF.Runtime.Alloc
2import ZlibF.Runtime.Tables
3import ZlibF.Zlib.«adler32.c»
4import ZlibF.Zlib.«inftrees.c»
5import ZlibF.Zlib.«zutil.c»
6import ZlibF.Zlib.«crc32.c»
7import ZlibF.Zlib.«inffast.c»
8
9/-!
10# inflate.c — faithful translation
11
12Source: `inflate.c` of the verified source (`zlib/` plus `patches/*.patch`; there is no `ub.patch` yet), default x86_64
13Linux build: `GUNZIP` defined, `Z_SOLO`, `PKZIP_BUG_WORKAROUND`, `INFLATE_STRICT`,
14`INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR`, `ZLIB_DEBUG` undefined (so `Tracev` is nothing and `dmax` is written but
15never read). Types as in `docs/design/translation.md`. The notes are `docs/proof/inflate.md`.
16
17## How the control flow is translated
18
19* `inflate()` keeps its registers (`next put have left hold bits in out`) and its other locals (`copy from here last len
20  ret`) in the record `IL`. A mode of the `switch` is one `def` (`inflate_HEAD`, ...) of the monad `X`, which is the
21  state monad on `IL` over the runtime monad `M` with an exception: `X α = ExceptT Ex (StateT IL M) α`.
22  * a mode that ends with `break` just returns;
23  * `goto inf_leave` is `throw Ex.leave` (the registers at that moment are kept: the state is not rolled back);
24  * `return v` is `throw (Ex.ret v)`;
25  * a fall-through is a tail call of the next mode (`TYPE` calls `TYPEDO` without writing the mode field);
26  * the macros are `def`s of `X` (`PULLBYTE`, `NEEDBITS`, `BITS`, ...), so a `goto` inside a macro is a `throw`.
27* Loops are the runtime's `cwhile` (through `xwhileBrk`, which carries the registers and the exit reason in the loop
28  state). `break` out of a `while` or `for (;;)` is the Boolean the body returns.
29* The next mode is read from the heap field `state->mode` on every trip of `for (;;)`, as in C.
30
31## Decisions (see the report with this file)
32
33* A pointer to a scalar field (`&state->next`, `&state->lenbits`, `&state->have`, `uInt *dictLength`) is passed as the
34  value in and returned as the value out.
35* `unsigned char hbuf[4]` and `unsigned char buf[4]` are byte blocks made at the declaration (`allocLocalB`, which never
36  fails; it uses the runtime's `allocBytes`) and freed before every return.
37* The local variables of `inflate()` that the C leaves uninitialised (`copy len from here last`) start as `0`, `NULL`,
38  `{0,0,0}`: an arbitrary value, as the guide allows; `from` starts null so that a use before assignment faults.
39* Only the default allocator is modelled (`zcalloc`/`zcfree` stored in the stream); another `zalloc`/`zfree` that the
40  code would call is `ub "custom allocator not modelled"`.
41* The cast of `strm->state` to `struct inflate_state *` faults if the state is a `deflate_state` (the C reads through
42  the wrong type, which is formally undefined).
43* `inflateCopy` compares `state->lencode` with `state->codes` with `>=` and `<=`, as the source does (no `ub.patch`).
44  Pointers into two different arrays are not comparable, so the comparison faults when `lencode` points to the static
45  `lenfix` (a stream stopped inside a fixed block): this is the real undefined behaviour of the source.
46* Error messages are string literals: `strm->msg` points to a fresh read-only block (`Zlib.Zutil.strLit`).
47-/
48
49namespace Zlib.Inflate
50open C
51open Zlib.Crc32 (crc32)
52open Zlib.Inffast (inflate_fast)
53open Zlib.Inftrees (inflate_table inflate_fixed)
54open Zlib.Adler32 (adler32)
55
56/-! ## Arithmetic with the checks of the C -/
57
58/-- `x << n` for `unsigned x`: faults if `n >= 32` (the count is out of range). -/
59def shl32 (x n : UInt32) : M UInt32 := if n < 32 then pure (x <<< n) else ub "shift count out of range"
60/-- `x >> n` for `unsigned x`. -/
61def shr32 (x n : UInt32) : M UInt32 := if n < 32 then pure (x >>> n) else ub "shift count out of range"
62/-- `x << n` for `unsigned long x`: faults if `n >= 64`. -/
63def shl64 (x : UInt64) (n : UInt32) : M UInt64 := if n < 64 then pure (x <<< n.toUInt64) else ub "shift count out of range"
64/-- `x >> n` for `unsigned long x`. -/
65def shr64 (x : UInt64) (n : UInt32) : M UInt64 := if n < 64 then pure (x >>> n.toUInt64) else ub "shift count out of range"
66/-- An `int` result: faults on signed overflow. -/
67def chkI32 (v : Int) : M Int32 :=
68  if -2147483648 ≤ v ∧ v < 2147483648 then pure (Int32.ofInt v) else ub "signed integer overflow"
69/-- A `long` result: faults on signed overflow. -/
70def chkI64 (v : Int) : M Int64 :=
71  if -9223372036854775808 ≤ v ∧ v < 9223372036854775808 then pure (Int64.ofInt v) else ub "signed integer overflow"
72/-- `(int)u` for `unsigned u` (modulo 2^32). -/
73def u2i (x : UInt32) : Int32 := Int32.ofInt (x.toNat : Int)
74/-- `(unsigned)i` for `int i`. -/
75def i2u (x : Int32) : UInt32 := x.toUInt32
76/-- `(unsigned long)i` for `int i` (sign extension, then modulo 2^64). -/
77def i2ul (x : Int32) : UInt64 := x.toInt64.toUInt64
78
79/-! ## The default allocator through the stream (`ZALLOC`, `ZFREE`) -/
80
81/-- `ZALLOC(strm, items, size)` for a byte block: calls `strm->zalloc`. Only `zcalloc` is modelled. -/
82def ZALLOCB (strm : ZStreamPtr) (items size : UInt32) : M BPtr := do
83  let z ← ldZStream strm
84  match z.zalloc with
85  | .fn "zcalloc" => Zlib.Zutil.zcalloc z.«opaque» items size
86  | _ => ub "custom allocator not modelled"
87
88/-- `ZALLOC(strm, 1, sizeof(struct inflate_state))`: uninitialised record (arbitrary integers, null pointers). -/
89def ZALLOCS (strm : ZStreamPtr) : M InflateStatePtr := do
90  let z ← ldZStream strm
91  match z.zalloc with
92  | .fn "zcalloc" => allocInflateState
93  | _ => ub "custom allocator not modelled"
94
95/-- `ZFREE(strm, addr)` for a byte block. -/
96def ZFREEB (strm : ZStreamPtr) (p : BPtr) : M Unit := do
97  let z ← ldZStream strm
98  match z.zfree with
99  | .fn "zcfree" => Zlib.Zutil.zcfree z.«opaque» p
100  | _ => ub "custom allocator not modelled"
101
102/-- `ZFREE(strm, state)` for an inflate state. -/
103def ZFREES (strm : ZStreamPtr) (st : InflateStatePtr) : M Unit := do
104  let z ← ldZStream strm
105  match z.zfree with
106  | .fn "zcfree" => freeInflateState st
107  | _ => ub "custom allocator not modelled"
108
109/-- A local array (`unsigned char hbuf[4]`): a writable block made at the declaration, with arbitrary content. It takes
110no allocation call of the failure oracle (a local cannot fail to exist); it uses the runtime's block allocator. -/
111def allocLocalB (n : Nat) : M BPtr := fun h =>
112  allocBytes (Array.ofFn (n := n) fun i => Junk.of (h.garbage h.nalloc i.val)) h
113
114/-- `strm->msg = (z_const char *)"..."`. -/
115def setMsg (strm : ZStreamPtr) (s : String) : M Unit := do
116  let p ← Zlib.Zutil.strLit s
117  let z ← ldZStream strm
118  stZStream strm { z with msg := p }
119
120/-! ## Access to the state and the stream -/
121
122/-- Read a field of `*st`. -/
123def rdS {α : Type} (st : InflateStatePtr) (f : InflateState → α) : M α := do return f (← ldInflateState st)
124/-- Update fields of `*st`. -/
125def wrS (st : InflateStatePtr) (f : InflateState → InflateState) : M Unit := do
126  let s ← ldInflateState st
127  stInflateState st (f s)
128/-- Read a field of `*strm`. -/
129def rdZ {α : Type} (strm : ZStreamPtr) (f : ZStream → α) : M α := do return f (← ldZStream strm)
130/-- Update fields of `*strm`. -/
131def wrZ (strm : ZStreamPtr) (f : ZStream → ZStream) : M Unit := do
132  let z ← ldZStream strm
133  stZStream strm (f z)
134
135/-- `state->lens` (a pointer to element 0 of the array field). -/
136def lensP (st : InflateStatePtr) : WPtr := match st with | some (.tab i) => .ref (.istate_lens i) 0 | none => .null
137/-- `state->work`. -/
138def workP (st : InflateStatePtr) : WPtr := match st with | some (.tab i) => .ref (.istate_work i) 0 | none => .null
139/-- `state->codes`. -/
140def codesP (st : InflateStatePtr) : CodePtr := match st with | some (.tab i) => .ref (.istate_codes i) 0 | none => .null
141
142/-- `static const unsigned short order[19]` -/
143def order : Array UInt16 := #[16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]
144/-- `order[i]`: faults outside the array. -/
145def orderAt (i : UInt32) : M UInt16 :=
146  match order[i.toNat]? with
147  | some v => pure v
148  | none => ub "order index outside its array"
149
150/-! ## `inflateStateCheck` .. `inflatePrime` -/
151
152/-- `local int inflateStateCheck(z_streamp strm)` -/
153def inflateStateCheck (strm : ZStreamPtr) : M Int32 := do
154  -- if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1;
155  if strm == none then return 1
156  let z ← ldZStream strm
157  if z.zalloc == .null || z.zfree == .null then return 1
158  -- state = (struct inflate_state FAR *)strm->state;
159  let state ← castInflateState z.state
160  -- if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1;
161  if state == none then return 1
162  let s ← ldInflateState state
163  if s.strm != strm || s.mode < HEAD || s.mode > SYNC then return 1
164  return 0
165
166/-- `int ZEXPORT inflateResetKeep(z_streamp strm)` -/
167def inflateResetKeep (strm : ZStreamPtr) : M Int32 := do
168  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
169  let z ← ldZStream strm
170  let state ← castInflateState z.state
171  -- strm->total_in = strm->total_out = state->total = 0;
172  wrS state fun s => { s with total := 0 }
173  -- strm->msg = Z_NULL; strm->data_type = 0;
174  wrZ strm fun z => { z with total_out := 0, total_in := 0, msg := .null, data_type := 0 }
175  -- if (state->wrap) strm->adler = state->wrap & 1;
176  let s ← ldInflateState state
177  if s.wrap != 0 then wrZ strm fun z => { z with adler := i2ul (s.wrap &&& 1) }
178  -- state->mode = HEAD; last = 0; havedict = 0; flags = -1; dmax = 32768U; head = Z_NULL; hold = 0; bits = 0;
179  -- state->lencode = state->distcode = state->next = state->codes;
180  -- state->sane = 1; state->back = -1;
181  wrS state fun s => { s with
182    mode := HEAD, last := 0, havedict := 0, flags := -1, dmax := 32768, head := none,
183    hold := 0, bits := 0, next := codesP state, distcode := codesP state, lencode := codesP state, sane := 1, back := -1 }
184  return Z_OK
185
186/-- `int ZEXPORT inflateReset(z_streamp strm)` -/
187def inflateReset (strm : ZStreamPtr) : M Int32 := do
188  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
189  let z ← ldZStream strm
190  let state ← castInflateState z.state
191  let s ← ldInflateState state
192  -- if (state->wbits != state->reqbits) { if (state->window != Z_NULL) { ZFREE; window = Z_NULL; } wbits = reqbits; }
193  if s.wbits != s.reqbits then
194    if s.window != .null then
195      ZFREEB strm s.window
196      wrS state fun s => { s with window := .null }
197    wrS state fun s => { s with wbits := s.reqbits }
198  -- state->wrap = state->reqwrap; wsize = 0; whave = 0; wnext = 0;
199  wrS state fun s => { s with wrap := s.reqwrap, wsize := 0, whave := 0, wnext := 0 }
200  return (← inflateResetKeep strm)
201
202/-- `int ZEXPORT inflateReset2(z_streamp strm, int windowBits)` -/
203def inflateReset2 (strm : ZStreamPtr) (windowBits : Int32) : M Int32 := do
204  -- if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
205  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
206  let z ← ldZStream strm
207  let state ← castInflateState z.state
208  let mut windowBits := windowBits
209  let mut wrap : Int32 := 0
210  -- if (windowBits < 0) { if (windowBits < -15) return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; }
211  if windowBits < 0 then
212    if windowBits < -15 then return Z_STREAM_ERROR
213    wrap := 0
214    windowBits ← chkI32 (-(windowBits.toInt))
215  else
216    -- wrap = (windowBits >> 4) + 5;
217    wrap ← chkI32 ((windowBits >>> 4).toInt + 5)
218    -- if (windowBits < 48) windowBits &= 15;
219    if windowBits < 48 then windowBits := windowBits &&& 15
220  -- if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR;
221  if windowBits != 0 && (windowBits < 8 || windowBits > 15) then return Z_STREAM_ERROR
222  -- if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE; window = Z_NULL; }
223  let s ← ldInflateState state
224  if s.window != .null && s.wbits != i2u windowBits then
225    ZFREEB strm s.window
226    wrS state fun s => { s with window := .null }
227  -- state->reqwrap = state->wrap = wrap; state->reqbits = state->wbits = (unsigned)windowBits;
228  wrS state fun s => { s with wrap := wrap, reqwrap := wrap, wbits := i2u windowBits, reqbits := i2u windowBits }
229  return (← inflateReset strm)
230
231/-- `int ZEXPORT inflateInit2_(z_streamp strm, int windowBits, const char *version, int stream_size)`
232(`version` is a pointer to a NUL-terminated string; `sizeof(z_stream)` is 112) -/
233def inflateInit2_ (strm : ZStreamPtr) (windowBits : Int32) (version : BPtr) (stream_size : Int32) : M Int32 := do
234  -- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR;
235  if version == .null then return Z_VERSION_ERROR
236  if (← index8 version 0) != 49 then return Z_VERSION_ERROR
237  if stream_size != 112 then return Z_VERSION_ERROR
238  -- if (strm == Z_NULL) return Z_STREAM_ERROR;
239  if strm == none then return Z_STREAM_ERROR
240  -- strm->msg = Z_NULL;
241  wrZ strm fun z => { z with msg := .null }
242  -- if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; }
243  if (← rdZ strm (·.zalloc)) == .null then
244    wrZ strm fun z => { z with zalloc := .fn "zcalloc", «opaque» := .null }
245  -- if (strm->zfree == (free_func)0) strm->zfree = zcfree;
246  if (← rdZ strm (·.zfree)) == .null then
247    wrZ strm fun z => { z with zfree := .fn "zcfree" }
248  -- state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state));
249  let state ← ZALLOCS strm
250  -- if (state == Z_NULL) return Z_MEM_ERROR;
251  if state == none then return Z_MEM_ERROR
252  -- zmemzero(state, sizeof(struct inflate_state));
253  stInflateState state (InflateState.zeroed)
254  -- strm->state = (struct internal_state FAR *)state;
255  wrZ strm fun z => { z with state := StateRef.ofInflateState state }
256  -- state->strm = strm; state->window = Z_NULL; state->mode = HEAD;
257  wrS state fun s => { s with strm := strm, window := .null, mode := HEAD }
258  -- ret = inflateReset2(strm, windowBits);
259  let ret ← inflateReset2 strm windowBits
260  -- if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; }
261  if ret != Z_OK then
262    ZFREES strm state
263    wrZ strm fun z => { z with state := none }
264  return ret
265
266/-- `int ZEXPORT inflateInit_(z_streamp strm, const char *version, int stream_size)` -/
267def inflateInit_ (strm : ZStreamPtr) (version : BPtr) (stream_size : Int32) : M Int32 :=
268  inflateInit2_ strm DEF_WBITS version stream_size
269
270/-- `int ZEXPORT inflatePrime(z_streamp strm, int bits, int value)` -/
271def inflatePrime (strm : ZStreamPtr) (bits : Int32) (value : Int32) : M Int32 := do
272  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
273  -- if (bits == 0) return Z_OK;
274  if bits == 0 then return Z_OK
275  let z ← ldZStream strm
276  let state ← castInflateState z.state
277  -- if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; }
278  if bits < 0 then
279    wrS state fun s => { s with hold := 0, bits := 0 }
280    return Z_OK
281  -- if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
282  let s ← ldInflateState state
283  if bits > 16 || s.bits + i2u bits > 32 then return Z_STREAM_ERROR
284  -- value &= (1L << bits) - 1;   (`long` arithmetic; bits is in 1..16)
285  let m : Int64 := ((1 : Int64) <<< bits.toInt64) - 1
286  let value : Int32 := (value.toInt64 &&& m).toInt32
287  -- state->hold += (unsigned long)value << state->bits;
288  let sh ← shl64 (i2ul value) s.bits
289  -- state->bits += (uInt)bits;
290  wrS state fun s => { s with hold := s.hold + sh, bits := s.bits + i2u bits }
291  return Z_OK
292
293/-- `local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy)` -/
294def updatewindow (strm : ZStreamPtr) (end_ : BPtr) (copy : UInt32) : M Int32 := do
295  let z ← ldZStream strm
296  let state ← castInflateState z.state
297  let s ← ldInflateState state
298  -- if (state->window == Z_NULL) { state->window = ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (...== Z_NULL) return 1; }
299  if s.window == .null then
300    let w ← ZALLOCB strm (← shl32 1 s.wbits) 1
301    wrS state fun s => { s with window := w }
302    if w == .null then return 1
303  -- if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; }
304  let s ← ldInflateState state
305  if s.wsize == 0 then
306    let ws ← shl32 1 s.wbits
307    wrS state fun s => { s with wsize := ws, wnext := 0, whave := 0 }
308  let s ← ldInflateState state
309  if copy >= s.wsize then
310    -- zmemcpy(state->window, end - state->wsize, state->wsize); wnext = 0; whave = wsize;
311    memcpyB s.window (← end_.add (-(s.wsize.toNat : Int))) s.wsize.toNat
312    wrS state fun s => { s with wnext := 0, whave := s.wsize }
313  else
314    -- dist = state->wsize - state->wnext; if (dist > copy) dist = copy;
315    let mut dist := s.wsize - s.wnext
316    if dist > copy then dist := copy
317    -- zmemcpy(state->window + state->wnext, end - copy, dist);
318    memcpyB (← s.window.add (s.wnext.toNat : Int)) (← end_.add (-(copy.toNat : Int))) dist.toNat
319    -- copy -= dist;
320    let copy := copy - dist
321    if copy != 0 then
322      -- zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize;
323      memcpyB s.window (← end_.add (-(copy.toNat : Int))) copy.toNat
324      wrS state fun s => { s with wnext := copy, whave := s.wsize }
325    else
326      -- state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist;
327      let mut wnext := s.wnext + dist
328      if wnext == s.wsize then wnext := 0
329      let mut whave := s.whave
330      if whave < s.wsize then whave := whave + dist
331      wrS state fun s => { s with wnext := wnext, whave := whave }
332  return 0
333
334/-! ## The registers of `inflate()` and the monad of its modes -/
335
336/-- How a mode leaves other than by `break`: `goto inf_leave`, or `return v`. -/
337inductive Ex where
338  | leave
339  | ret (v : Int32)
340
341/-- The locals of `inflate()` (and of `inflateBack()`): `next put have left hold bits in out copy from here last len
342ret`. `have` and `in` are keywords, so `have_` and `in_`; `out` is `out_` for symmetry. -/
343structure IL where
344  next : BPtr
345  put : BPtr
346  have_ : UInt32
347  left : UInt32
348  hold : UInt64
349  bits : UInt32
350  in_ : UInt32
351  out_ : UInt32
352  copy : UInt32
353  from_ : BPtr
354  here : Code
355  last : Code
356  len : UInt32
357  ret : Int32
358
359/-- The registers before the first assignment (the C leaves these uninitialised; see the file comment). -/
360def IL.init : IL where
361  next := .null
362  put := .null
363  have_ := 0
364  left := 0
365  hold := 0
366  bits := 0
367  in_ := 0
368  out_ := 0
369  copy := 0
370  from_ := .null
371  here := default
372  last := default
373  len := 0
374  ret := 0
375
376/-- The monad of a mode: the registers, `goto inf_leave` / `return` as an exception, and the heap. -/
377abbrev X := ExceptT Ex (StateT IL M)
378
379/-- Why a loop of `X` ended. -/
380inductive Stop where
381  | go
382  | brk
383  | ex (e : Ex)
384
385/-- `while (cond) body` where `body` returns `true` for `break`. Built on the runtime's `cwhile`; the registers and the
386reason for stopping are the loop-carried state, so a `goto` or `return` inside leaves with the registers it had. -/
387def xwhileBrk (cond : X Bool) (body : X Bool) : X Unit :=
388  ExceptT.mk (fun l0 => do
389    let r ← cwhile (σ := IL × Stop)
390      (fun (l, s) => match s with
391        | .go => do
392          let (r, l') ← StateT.run (ExceptT.run cond) l
393          pure (match r with
394            | .ok b => (b, (l', Stop.go))
395            | .error e => (false, (l', Stop.ex e)))
396        | s => pure (false, (l, s)))
397      (fun (l, _) => do
398        let (r, l') ← StateT.run (ExceptT.run body) l
399        pure (match r with
400          | .ok b => (l', if b then Stop.brk else Stop.go)
401          | .error e => (l', Stop.ex e)))
402      (l0, Stop.go)
403    let (l, s) := r
404    pure (match s with
405      | .ex e => (Except.error e, l)
406      | _ => (Except.ok (), l)))
407
408/-- `while (cond) body` -/
409def xwhile (cond : X Bool) (body : X Unit) : X Unit := xwhileBrk cond (do body; pure false)
410
411/-- `do body while (cond)` -/
412def xdoWhile (body : X Unit) (cond : X Bool) : X Unit := do
413  body
414  xwhile cond body
415
416/-- `for (;;) body` where `body` returns `true` for `break`. -/
417def xloopBrk (body : X Bool) : X Unit := xwhileBrk (pure true) body
418
419/-- The information `inflate()` and its macros share. -/
420structure Ctx where
421  strm : ZStreamPtr
422  st : InflateStatePtr
423  hbuf : BPtr
424  flush : Int32
425
426/-! ## The macros of `inflate.c`, each one a `def` -/
427
428/-- `LOAD()` -/
429def LOAD (strm : ZStreamPtr) (st : InflateStatePtr) : X Unit := do
430  let z ← ldZStream strm
431  let s ← ldInflateState st
432  modify fun l => { l with
433    put := z.next_out, left := z.avail_out, next := z.next_in, have_ := z.avail_in,
434    hold := s.hold, bits := s.bits }
435
436/-- `RESTORE()` -/
437def RESTORE (strm : ZStreamPtr) (st : InflateStatePtr) : X Unit := do
438  let l ← get
439  wrZ strm fun z => { z with next_out := l.put, avail_out := l.left, next_in := l.next, avail_in := l.have_ }
440  wrS st fun s => { s with hold := l.hold, bits := l.bits }
441
442/-- `INITBITS()` -/
443def INITBITS : X Unit := modify fun l => { l with hold := 0, bits := 0 }
444
445/-- `PULLBYTE()`: `goto inf_leave` if there is no input. -/
446def PULLBYTE : X Unit := do
447  let l ← get
448  if l.have_ == 0 then throw Ex.leave
449  -- have--;
450  set { l with have_ := l.have_ - 1 }
451  -- hold += (unsigned long)(*next++) << bits; bits += 8;
452  let b ← load8 l.next
453  let nx ← l.next.add 1
454  let sh ← shl64 b.toUInt64 l.bits
455  set { l with have_ := l.have_ - 1, next := nx, hold := l.hold + sh, bits := l.bits + 8 }
456
457/-- `NEEDBITS(n)`: `while (bits < (unsigned)(n)) PULLBYTE();` -/
458def NEEDBITS (n : UInt32) : X Unit :=
459  xwhile (do return (← get).bits < n) PULLBYTE
460
461/-- `BITS(n)`: `((unsigned)hold & ((1U << (n)) - 1))` -/
462def BITS (n : UInt32) : X UInt32 := do
463  let l ← get
464  let m ← shl32 1 n
465  return l.hold.toUInt32 &&& (m - 1)
466
467/-- `DROPBITS(n)`: `hold >>= (n); bits -= (unsigned)(n);` -/
468def DROPBITS (n : UInt32) : X Unit := do
469  let l ← get
470  let h ← shr64 l.hold n
471  set { l with hold := h, bits := l.bits - n }
472
473/-- `BYTEBITS()`: `hold >>= bits & 7; bits -= bits & 7;` -/
474def BYTEBITS : X Unit := do
475  let l ← get
476  let h ← shr64 l.hold (l.bits &&& 7)
477  set { l with hold := h, bits := l.bits - (l.bits &&& 7) }
478
479/-- `ZSWAP32(q)` -/
480def ZSWAP32 (q : UInt64) : UInt64 :=
481  ((q >>> 24) &&& (0xff : UInt64)) + ((q >>> 8) &&& (0xff00 : UInt64)) + ((q &&& (0xff00 : UInt64)) <<< 8) + ((q &&& (0xff : UInt64)) <<< 24)
482
483/-- `UPDATE_CHECK(check, buf, len)`: `(state->flags ? crc32(check, buf, len) : adler32(check, buf, len))` -/
484def UPDATE_CHECK (st : InflateStatePtr) (check : UInt64) (buf : BPtr) (len : UInt32) : M UInt64 := do
485  if (← rdS st (·.flags)) != 0 then crc32 check buf len else adler32 check buf len
486
487/-- `CRC2(state->check, hold)` -/
488def CRC2 (c : Ctx) : X Unit := do
489  let l ← get
490  -- hbuf[0] = (unsigned char)(word); hbuf[1] = (unsigned char)((word) >> 8);
491  store8 c.hbuf l.hold.toUInt8
492  store8 (← c.hbuf.add 1) (l.hold >>> 8).toUInt8
493  -- check = crc32(check, hbuf, 2);
494  let ck ← rdS c.st (·.check)
495  let v ← crc32 ck c.hbuf 2
496  wrS c.st fun s => { s with check := v }
497
498/-- `CRC4(state->check, hold)` -/
499def CRC4 (c : Ctx) : X Unit := do
500  let l ← get
501  store8 c.hbuf l.hold.toUInt8
502  store8 (← c.hbuf.add 1) (l.hold >>> 8).toUInt8
503  store8 (← c.hbuf.add 2) (l.hold >>> 16).toUInt8
504  store8 (← c.hbuf.add 3) (l.hold >>> 24).toUInt8
505  let ck ← rdS c.st (·.check)
506  let v ← crc32 ck c.hbuf 4
507  wrS c.st fun s => { s with check := v }
508
509/-- `(state->flags & 0x0200) && (state->wrap & 4)` -/
510def hcrcOn (st : InflateStatePtr) : M Bool := do
511  let s ← ldInflateState st
512  return (s.flags &&& 0x0200) != 0 && (s.wrap &&& 4) != 0
513
514/-- `state->mode = m;` -/
515def setMode (st : InflateStatePtr) (m : UInt32) : M Unit := wrS st fun s => { s with mode := m }
516
517/-- `strm->msg = "..."; state->mode = BAD;` -/
518def badMode (c : Ctx) (msg : String) : M Unit := do
519  setMsg c.strm msg
520  setMode c.st BAD
521
522/-! ## The modes of `inflate()`, from the last to the first (a fall-through is a tail call) -/
523
524/-- `case DONE:` -/
525def inflate_DONE (_c : Ctx) : X Unit := do
526  -- ret = Z_STREAM_END; goto inf_leave;
527  modify fun l => { l with ret := Z_STREAM_END }
528  throw Ex.leave
529
530/-- `case LENGTH:` -/
531def inflate_LENGTH (c : Ctx) : X Unit := do
532  -- if (state->wrap && state->flags) {
533  let s ← ldInflateState c.st
534  if s.wrap != 0 && s.flags != 0 then
535    NEEDBITS 32
536    -- if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) { ...BAD; break; }
537    let s ← ldInflateState c.st
538    let l ← get
539    if (s.wrap &&& 4) != 0 && l.hold != (s.total &&& 0xffffffff) then
540      badMode c "incorrect length check"
541      return
542    INITBITS
543  -- state->mode = DONE; /* fallthrough */
544  setMode c.st DONE
545  inflate_DONE c
546
547/-- `case CHECK:` -/
548def inflate_CHECK (c : Ctx) : X Unit := do
549  let s ← ldInflateState c.st
550  -- if (state->wrap) {
551  if s.wrap != 0 then
552    NEEDBITS 32
553    -- out -= left;
554    modify fun l => { l with out_ := l.out_ - l.left }
555    let l ← get
556    -- strm->total_out += out; state->total += out;
557    wrZ c.strm fun z => { z with total_out := z.total_out + l.out_.toUInt64 }
558    wrS c.st fun s => { s with total := s.total + l.out_.toUInt64 }
559    -- if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, put - out, out);
560    let s ← ldInflateState c.st
561    if (s.wrap &&& 4) != 0 && l.out_ != 0 then
562      let p ← l.put.add (-(l.out_.toNat : Int))
563      let v ← UPDATE_CHECK c.st s.check p l.out_
564      wrS c.st fun s => { s with check := v }
565      wrZ c.strm fun z => { z with adler := v }
566    -- out = left;
567    modify fun l => { l with out_ := l.left }
568    -- if ((state->wrap & 4) && ((state->flags ? hold : ZSWAP32(hold)) != state->check)) { ...BAD; break; }
569    let s ← ldInflateState c.st
570    let l ← get
571    if (s.wrap &&& 4) != 0 && (if s.flags != 0 then l.hold else ZSWAP32 l.hold) != s.check then
572      badMode c "incorrect data check"
573      return
574    INITBITS
575  -- state->mode = LENGTH; /* fallthrough */
576  setMode c.st LENGTH
577  inflate_LENGTH c
578
579/-- `case LIT:` -/
580def inflate_LIT (c : Ctx) : X Unit := do
581  let l ← get
582  -- if (left == 0) goto inf_leave;
583  if l.left == 0 then throw Ex.leave
584  -- *put++ = (unsigned char)(state->length);
585  let s ← ldInflateState c.st
586  store8 l.put s.length.toUInt8
587  let p ← l.put.add 1
588  -- left--; state->mode = LEN;
589  set { l with put := p, left := l.left - 1 }
590  setMode c.st LEN
591
592/-- `case MATCH:` -/
593def inflate_MATCH (c : Ctx) : X Unit := do
594  let l ← get
595  -- if (left == 0) goto inf_leave;
596  if l.left == 0 then throw Ex.leave
597  -- copy = out - left;
598  let mut copy := l.out_ - l.left
599  let mut from_ : BPtr := l.from_
600  let s ← ldInflateState c.st
601  -- if (state->offset > copy) { /* copy from window */
602  if s.offset > copy then
603    -- copy = state->offset - copy;
604    copy := s.offset - copy
605    -- if (copy > state->whave) { if (state->sane) { ...BAD; break; } }
606    if copy > s.whave then
607      if s.sane != 0 then
608        badMode c "invalid distance too far back"
609        return
610    -- if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); }
611    if copy > s.wnext then
612      copy := copy - s.wnext
613      from_ ← s.window.add ((s.wsize - copy).toNat : Int)
614    else
615      -- else from = state->window + (state->wnext - copy);
616      from_ ← s.window.add ((s.wnext - copy).toNat : Int)
617    -- if (copy > state->length) copy = state->length;
618    if copy > s.length then copy := s.length
619  else
620    -- from = put - state->offset; copy = state->length;
621    from_ ← l.put.add (-(s.offset.toNat : Int))
622    copy := s.length
623  -- if (copy > left) copy = left;
624  if copy > l.left then copy := l.left
625  -- left -= copy; state->length -= copy;
626  set { l with left := l.left - copy, copy := copy, from_ := from_ }
627  wrS c.st fun s => { s with length := s.length - copy }
628  -- do { *put++ = *from++; } while (--copy);
629  xdoWhile
630    (do
631      let l ← get
632      let b ← load8 l.from_
633      store8 l.put b
634      let p ← l.put.add 1
635      let f ← l.from_.add 1
636      set { l with put := p, from_ := f })
637    (do
638      let l ← get
639      let n := l.copy - 1
640      set { l with copy := n }
641      return n != 0)
642  -- if (state->length == 0) state->mode = LEN;
643  if (← rdS c.st (·.length)) == 0 then setMode c.st LEN
644
645/-- The bit-extraction part shared in spirit by `LENEXT` and `DISTEXT`: `if (state->extra) { NEEDBITS(state->extra); ...}`.
646`case DISTEXT:` -/
647def inflate_DISTEXT (c : Ctx) : X Unit := do
648  let s ← ldInflateState c.st
649  -- if (state->extra) {
650  if s.extra != 0 then
651    NEEDBITS s.extra
652    -- state->offset += BITS(state->extra);
653    let b ← BITS s.extra
654    wrS c.st fun s => { s with offset := s.offset + b }
655    -- DROPBITS(state->extra);
656    DROPBITS s.extra
657    -- state->back += state->extra;   (`int += unsigned`: computed in unsigned, converted back)
658    wrS c.st fun s => { s with back := u2i (i2u s.back + s.extra) }
659  -- state->mode = MATCH; /* fallthrough */
660  setMode c.st MATCH
661  inflate_MATCH c
662
663/-- The two-level table lookup `for (;;) { here = TABLE[BITS(bitsOfTable)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); }`.
664`dist` selects `distcode`/`distbits`, else `lencode`/`lenbits`. -/
665def lookup1 (c : Ctx) (dist : Bool) : X Unit :=
666  xloopBrk (do
667    let s ← ldInflateState c.st
668    let tab := if dist then s.distcode else s.lencode
669    let nb := if dist then s.distbits else s.lenbits
670    let b ← BITS nb
671    let here ← Ptr.index tab (b.toNat : Int)
672    modify fun l => { l with here := here }
673    if here.bits.toUInt32 <= (← get).bits then return true
674    PULLBYTE
675    return false)
676
677/-- `for (;;) { here = TABLE[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); }` -/
678def lookup2 (c : Ctx) (dist : Bool) : X Unit :=
679  xloopBrk (do
680    let s ← ldInflateState c.st
681    let tab := if dist then s.distcode else s.lencode
682    let last := (← get).last
683    let b ← BITS (last.bits.toUInt32 + last.op.toUInt32)
684    let sh ← shr32 b last.bits.toUInt32
685    let here ← Ptr.index tab ((last.val.toUInt32 + sh).toNat : Int)
686    modify fun l => { l with here := here }
687    if (last.bits.toUInt32 + here.bits.toUInt32) <= (← get).bits then return true
688    PULLBYTE
689    return false)
690
691/-- `case DIST:` -/
692def inflate_DIST (c : Ctx) : X Unit := do
693  lookup1 c true
694  let here := (← get).here
695  -- if ((here.op & 0xf0) == 0) {
696  if (here.op &&& 0xf0) == 0 then
697    modify fun l => { l with last := here }
698    lookup2 c true
699    let last := (← get).last
700    DROPBITS last.bits.toUInt32
701    let s ← ldInflateState c.st
702    let bk ← chkI32 (s.back.toInt + last.bits.toNat)
703    wrS c.st fun s => { s with back := bk }
704  -- DROPBITS(here.bits); state->back += here.bits;
705  let here := (← get).here
706  DROPBITS here.bits.toUInt32
707  let s ← ldInflateState c.st
708  let bk ← chkI32 (s.back.toInt + here.bits.toNat)
709  wrS c.st fun s => { s with back := bk }
710  -- if (here.op & 64) { ...BAD; break; }
711  if (here.op &&& 64) != 0 then
712    badMode c "invalid distance code"
713    return
714  -- state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT;
715  wrS c.st fun s => { s with offset := here.val.toUInt32, extra := here.op.toUInt32 &&& 15 }
716  setMode c.st DISTEXT
717  inflate_DISTEXT c
718
719/-- `case LENEXT:` -/
720def inflate_LENEXT (c : Ctx) : X Unit := do
721  let s ← ldInflateState c.st
722  if s.extra != 0 then
723    NEEDBITS s.extra
724    -- state->length += BITS(state->extra);
725    let b ← BITS s.extra
726    wrS c.st fun s => { s with length := s.length + b }
727    DROPBITS s.extra
728    wrS c.st fun s => { s with back := u2i (i2u s.back + s.extra) }
729  -- state->was = state->length; state->mode = DIST; /* fallthrough */
730  wrS c.st fun s => { s with was := s.length, mode := DIST }
731  inflate_DIST c
732
733/-- `case LEN:` -/
734def inflate_LEN (c : Ctx) : X Unit := do
735  let l ← get
736  -- if (have >= 6 && left >= 258 && bits < 8) { RESTORE(); inflate_fast(strm, out); LOAD(); ...; break; }
737  if l.have_ >= 6 && l.left >= 258 && l.bits < 8 then
738    RESTORE c.strm c.st
739    inflate_fast c.strm l.out_
740    LOAD c.strm c.st
741    -- if (state->mode == TYPE) state->back = -1;
742    if (← rdS c.st (·.mode)) == TYPE then wrS c.st fun s => { s with back := -1 }
743    return
744  -- state->back = 0;
745  wrS c.st fun s => { s with back := 0 }
746  lookup1 c false
747  let here := (← get).here
748  -- if (here.op && (here.op & 0xf0) == 0) {
749  if here.op != 0 && (here.op &&& 0xf0) == 0 then
750    modify fun l => { l with last := here }
751    lookup2 c false
752    let last := (← get).last
753    DROPBITS last.bits.toUInt32
754    let s ← ldInflateState c.st
755    let bk ← chkI32 (s.back.toInt + last.bits.toNat)
756    wrS c.st fun s => { s with back := bk }
757  -- DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val;
758  let here := (← get).here
759  DROPBITS here.bits.toUInt32
760  let s ← ldInflateState c.st
761  let bk ← chkI32 (s.back.toInt + here.bits.toNat)
762  wrS c.st fun s => { s with back := bk, length := here.val.toUInt32 }
763  -- if ((int)(here.op) == 0) { state->mode = LIT; break; }
764  if here.op.toNat == 0 then
765    setMode c.st LIT
766    return
767  -- if (here.op & 32) { state->back = -1; state->mode = TYPE; break; }
768  if (here.op &&& 32) != 0 then
769    wrS c.st fun s => { s with back := -1, mode := TYPE }
770    return
771  -- if (here.op & 64) { ...BAD; break; }
772  if (here.op &&& 64) != 0 then
773    badMode c "invalid literal/length code"
774    return
775  -- state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; /* fallthrough */
776  wrS c.st fun s => { s with extra := here.op.toUInt32 &&& 15, mode := LENEXT }
777  inflate_LENEXT c
778
779/-- `case LEN_:` -/
780def inflate_LEN_ (c : Ctx) : X Unit := do
781  setMode c.st LEN
782  inflate_LEN c
783
784/-- `case CODELENS:` -/
785def inflate_CODELENS (c : Ctx) : X Unit := do
786  -- while (state->have < state->nlen + state->ndist) {
787  xwhileBrk
788    (do let s ← ldInflateState c.st; return s.have < s.nlen + s.ndist)
789    (do
790      lookup1 c false
791      let here := (← get).here
792      -- if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; }
793      if here.val < 16 then
794        DROPBITS here.bits.toUInt32
795        let s ← ldInflateState c.st
796        Ptr.store (← (lensP c.st).add (s.have.toNat : Int)) here.val
797        wrS c.st fun s => { s with «have» := s.«have» + 1 }
798        return false
799      else
800        if here.val == 16 then
801          NEEDBITS (here.bits.toUInt32 + 2)
802          DROPBITS here.bits.toUInt32
803          -- if (state->have == 0) { "invalid bit length repeat"; BAD; break; }
804          let s ← ldInflateState c.st
805          if s.«have» == 0 then
806            badMode c "invalid bit length repeat"
807            return true
808          -- len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2);
809          let v ← Ptr.index (lensP c.st) ((s.«have» - 1).toNat : Int)
810          let b ← BITS 2
811          modify fun l => { l with len := v.toUInt32, copy := 3 + b }
812          DROPBITS 2
813        else if here.val == 17 then
814          NEEDBITS (here.bits.toUInt32 + 3)
815          DROPBITS here.bits.toUInt32
816          let b ← BITS 3
817          modify fun l => { l with len := 0, copy := 3 + b }
818          DROPBITS 3
819        else
820          NEEDBITS (here.bits.toUInt32 + 7)
821          DROPBITS here.bits.toUInt32
822          let b ← BITS 7
823          modify fun l => { l with len := 0, copy := 11 + b }
824          DROPBITS 7
825        -- if (state->have + copy > state->nlen + state->ndist) { "invalid bit length repeat"; BAD; break; }
826        let s ← ldInflateState c.st
827        if s.«have» + (← get).copy > s.nlen + s.ndist then
828          badMode c "invalid bit length repeat"
829          return true
830        -- while (copy--) state->lens[state->have++] = (unsigned short)len;
831        xwhile
832          (do
833            let l ← get
834            set { l with copy := l.copy - 1 }
835            return l.copy != 0)
836          (do
837            let s ← ldInflateState c.st
838            Ptr.store (← (lensP c.st).add (s.«have».toNat : Int)) (← get).len.toUInt16
839            wrS c.st fun s => { s with «have» := s.«have» + 1 })
840        return false)
841  -- if (state->mode == BAD) break;
842  if (← rdS c.st (·.mode)) == BAD then return
843  -- if (state->lens[256] == 0) { "invalid code -- missing end-of-block"; BAD; break; }
844  if (← Ptr.index (lensP c.st) 256) == (0 : UInt16) then
845    badMode c "invalid code -- missing end-of-block"
846    return
847  -- state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9;
848  wrS c.st fun s => { s with next := codesP c.st, lencode := codesP c.st, lenbits := 9 }
849  -- ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work);
850  let s ← ldInflateState c.st
851  let (r, nx, lb) ← inflate_table LENS (lensP c.st) s.nlen s.next s.lenbits (workP c.st)
852  wrS c.st fun s => { s with next := nx, lenbits := lb }
853  modify fun l => { l with ret := r }
854  -- if (ret) { "invalid literal/lengths set"; BAD; break; }
855  if r != 0 then
856    badMode c "invalid literal/lengths set"
857    return
858  -- state->distcode = (const code FAR *)(state->next); state->distbits = 6;
859  wrS c.st fun s => { s with distcode := s.next, distbits := 6 }
860  -- ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work);
861  let s ← ldInflateState c.st
862  let (r, nx, db) ← inflate_table DISTS (← (lensP c.st).add (s.nlen.toNat : Int)) s.ndist s.next s.distbits (workP c.st)
863  wrS c.st fun s => { s with next := nx, distbits := db }
864  modify fun l => { l with ret := r }
865  if r != 0 then
866    badMode c "invalid distances set"
867    return
868  -- state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */
869  setMode c.st LEN_
870  if c.flush == Z_TREES then throw Ex.leave
871  inflate_LEN_ c
872
873/-- `case LENLENS:` -/
874def inflate_LENLENS (c : Ctx) : X Unit := do
875  -- while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); }
876  xwhile
877    (do let s ← ldInflateState c.st; return s.«have» < s.ncode)
878    (do
879      NEEDBITS 3
880      let s ← ldInflateState c.st
881      wrS c.st fun s => { s with «have» := s.«have» + 1 }
882      let o ← orderAt s.«have»
883      let b ← BITS 3
884      Ptr.store (← (lensP c.st).add (o.toNat : Int)) b.toUInt16
885      DROPBITS 3)
886  -- while (state->have < 19) state->lens[order[state->have++]] = 0;
887  xwhile
888    (do let s ← ldInflateState c.st; return s.«have» < 19)
889    (do
890      let s ← ldInflateState c.st
891      wrS c.st fun s => { s with «have» := s.«have» + 1 }
892      let o ← orderAt s.«have»
893      Ptr.store (← (lensP c.st).add (o.toNat : Int)) (0 : UInt16))
894  -- state->next = state->codes; state->lencode = state->distcode = (const code FAR *)(state->next); state->lenbits = 7;
895  wrS c.st fun s => { s with next := codesP c.st, distcode := codesP c.st, lencode := codesP c.st, lenbits := 7 }
896  -- ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work);
897  let s ← ldInflateState c.st
898  let (r, nx, lb) ← inflate_table CODES (lensP c.st) 19 s.next s.lenbits (workP c.st)
899  wrS c.st fun s => { s with next := nx, lenbits := lb }
900  modify fun l => { l with ret := r }
901  -- if (ret) { "invalid code lengths set"; BAD; break; }
902  if r != 0 then
903    badMode c "invalid code lengths set"
904    return
905  -- state->have = 0; state->mode = CODELENS; /* fallthrough */
906  wrS c.st fun s => { s with «have» := 0, mode := CODELENS }
907  inflate_CODELENS c
908
909/-- `case TABLE:` -/
910def inflate_TABLE (c : Ctx) : X Unit := do
911  NEEDBITS 14
912  -- state->nlen = BITS(5) + 257; DROPBITS(5);
913  let b ← BITS 5
914  wrS c.st fun s => { s with nlen := b + 257 }
915  DROPBITS 5
916  -- state->ndist = BITS(5) + 1; DROPBITS(5);
917  let b ← BITS 5
918  wrS c.st fun s => { s with ndist := b + 1 }
919  DROPBITS 5
920  -- state->ncode = BITS(4) + 4; DROPBITS(4);
921  let b ← BITS 4
922  wrS c.st fun s => { s with ncode := b + 4 }
923  DROPBITS 4
924  -- if (state->nlen > 286 || state->ndist > 30) { "too many length or distance symbols"; BAD; break; }
925  let s ← ldInflateState c.st
926  if s.nlen > 286 || s.ndist > 30 then
927    badMode c "too many length or distance symbols"
928    return
929  -- state->have = 0; state->mode = LENLENS; /* fallthrough */
930  wrS c.st fun s => { s with «have» := 0, mode := LENLENS }
931  inflate_LENLENS c
932
933/-- `case COPY:` -/
934def inflate_COPY (c : Ctx) : X Unit := do
935  -- copy = state->length;
936  let s ← ldInflateState c.st
937  let mut copy := s.length
938  -- if (copy) {
939  if copy != 0 then
940    let l ← get
941    if copy > l.have_ then copy := l.have_
942    if copy > l.left then copy := l.left
943    -- if (copy == 0) goto inf_leave;
944    if copy == 0 then
945      set { l with copy := copy }
946      throw Ex.leave
947    -- zmemcpy(put, next, copy);
948    memcpyB l.put l.next copy.toNat
949    -- have -= copy; next += copy; left -= copy; put += copy; state->length -= copy;
950    let nx ← l.next.add (copy.toNat : Int)
951    let pt ← l.put.add (copy.toNat : Int)
952    set { l with copy := copy, have_ := l.have_ - copy, next := nx, left := l.left - copy, put := pt }
953    wrS c.st fun s => { s with length := s.length - copy }
954    return
955  modify fun l => { l with copy := copy }
956  -- state->mode = TYPE; break;
957  setMode c.st TYPE
958
959/-- `case COPY_:` -/
960def inflate_COPY_ (c : Ctx) : X Unit := do
961  setMode c.st COPY
962  inflate_COPY c
963
964/-- `case STORED:` -/
965def inflate_STORED (c : Ctx) : X Unit := do
966  BYTEBITS
967  NEEDBITS 32
968  let l ← get
969  -- if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { "invalid stored block lengths"; BAD; break; }
970  if (l.hold &&& (0xffff : UInt64)) != ((l.hold >>> 16) ^^^ (0xffff : UInt64)) then
971    badMode c "invalid stored block lengths"
972    return
973  -- state->length = (unsigned)hold & 0xffff;
974  wrS c.st fun s => { s with length := l.hold.toUInt32 &&& 0xffff }
975  INITBITS
976  -- state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; /* fallthrough */
977  setMode c.st COPY_
978  if c.flush == Z_TREES then throw Ex.leave
979  inflate_COPY_ c
980
981/-- `case TYPEDO:` -/
982def inflate_TYPEDO (c : Ctx) : X Unit := do
983  -- if (state->last) { BYTEBITS(); state->mode = CHECK; break; }
984  if (← rdS c.st (·.last)) != 0 then
985    BYTEBITS
986    setMode c.st CHECK
987    return
988  NEEDBITS 3
989  -- state->last = BITS(1); DROPBITS(1);
990  let b ← BITS 1
991  wrS c.st fun s => { s with last := u2i b }
992  DROPBITS 1
993  -- switch (BITS(2)) {
994  match (← BITS 2) with
995  | 0 => setMode c.st STORED
996  | 1 =>
997    inflate_fixed c.st
998    setMode c.st LEN_
999    -- if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; }
1000    if c.flush == Z_TREES then
1001      DROPBITS 2
1002      throw Ex.leave
1003  | 2 => setMode c.st TABLE
1004  | _ => badMode c "invalid block type"
1005  -- DROPBITS(2); break;
1006  DROPBITS 2
1007
1008/-- `case TYPE:` -/
1009def inflate_TYPE (c : Ctx) : X Unit := do
1010  -- if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; /* fallthrough, the mode is not written */
1011  if c.flush == Z_BLOCK || c.flush == Z_TREES then throw Ex.leave
1012  inflate_TYPEDO c
1013
1014/-- `case DICT:` -/
1015def inflate_DICT (c : Ctx) : X Unit := do
1016  -- if (state->havedict == 0) { RESTORE(); strm->total_in += in - strm->avail_in; return Z_NEED_DICT; }
1017  if (← rdS c.st (·.havedict)) == 0 then
1018    RESTORE c.strm c.st
1019    let l ← get
1020    wrZ c.strm fun z => { z with total_in := z.total_in + (l.in_ - z.avail_in).toUInt64 }
1021    throw (Ex.ret Z_NEED_DICT)
1022  -- strm->adler = state->check = adler32(0L, Z_NULL, 0);
1023  let v ← adler32 0 .null 0
1024  wrS c.st fun s => { s with check := v }
1025  wrZ c.strm fun z => { z with adler := v }
1026  -- state->mode = TYPE; /* fallthrough */
1027  setMode c.st TYPE
1028  inflate_TYPE c
1029
1030/-- `case DICTID:` -/
1031def inflate_DICTID (c : Ctx) : X Unit := do
1032  NEEDBITS 32
1033  -- strm->adler = state->check = ZSWAP32(hold);
1034  let v := ZSWAP32 (← get).hold
1035  wrS c.st fun s => { s with check := v }
1036  wrZ c.strm fun z => { z with adler := v }
1037  INITBITS
1038  setMode c.st DICT
1039  inflate_DICT c
1040
1041/-- `case HCRC:` -/
1042def inflate_HCRC (c : Ctx) : X Unit := do
1043  -- if (state->flags & 0x0200) {
1044  if ((← rdS c.st (·.flags)) &&& 0x0200) != 0 then
1045    NEEDBITS 16
1046    let s ← ldInflateState c.st
1047    -- if ((state->wrap & 4) && hold != (state->check & 0xffff)) { "header crc mismatch"; BAD; break; }
1048    if (s.wrap &&& 4) != 0 && (← get).hold != (s.check &&& 0xffff) then
1049      badMode c "header crc mismatch"
1050      return
1051    INITBITS
1052  -- if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; }
1053  let s ← ldInflateState c.st
1054  if s.head != none then
1055    let g ← ldGzHeader s.head
1056    stGzHeader s.head { g with hcrc := (s.flags >>> 9) &&& 1, done := 1 }
1057  -- strm->adler = state->check = crc32(0L, Z_NULL, 0);
1058  let v ← crc32 0 .null 0
1059  wrS c.st fun s => { s with check := v }
1060  wrZ c.strm fun z => { z with adler := v }
1061  -- state->mode = TYPE; break;
1062  setMode c.st TYPE
1063
1064/-- `case COMMENT:` -/
1065def inflate_COMMENT (c : Ctx) : X Unit := do
1066  -- if (state->flags & 0x1000) {
1067  if ((← rdS c.st (·.flags)) &&& 0x1000) != 0 then
1068    -- if (have == 0) goto inf_leave; copy = 0;
1069    if (← get).have_ == 0 then throw Ex.leave
1070    modify fun l => { l with copy := 0 }
1071    -- do { len = (unsigned)(next[copy++]); if (head && head->comment && length < comm_max) head->comment[length++] = (Bytef)len; } while (len && copy < have);
1072    xdoWhile
1073      (do
1074        let l ← get
1075        let b ← index8 l.next l.copy.toNat
1076        set { l with len := b.toUInt32, copy := l.copy + 1 }
1077        let s ← ldInflateState c.st
1078        if s.head != none then
1079          let g ← ldGzHeader s.head
1080          if g.comment != .null && s.length < g.comm_max then
1081            store8 (← g.comment.add (s.length.toNat : Int)) b
1082            wrS c.st fun s => { s with length := s.length + 1 })
1083      (do let l ← get; return l.len != 0 && l.copy < l.have_)
1084    -- if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy);
1085    if ← hcrcOn c.st then
1086      let l ← get
1087      let v ← crc32 (← rdS c.st (·.check)) l.next l.copy
1088      wrS c.st fun s => { s with check := v }
1089    -- have -= copy; next += copy; if (len) goto inf_leave;
1090    let l ← get
1091    let nx ← l.next.add (l.copy.toNat : Int)
1092    set { l with have_ := l.have_ - l.copy, next := nx }
1093    if l.len != 0 then throw Ex.leave
1094  else
1095    -- else if (state->head != Z_NULL) state->head->comment = Z_NULL;
1096    let s ← ldInflateState c.st
1097    if s.head != none then
1098      let g ← ldGzHeader s.head
1099      stGzHeader s.head { g with comment := .null }
1100  -- state->mode = HCRC; /* fallthrough */
1101  setMode c.st HCRC
1102  inflate_HCRC c
1103
1104/-- `case NAME:` -/
1105def inflate_NAME (c : Ctx) : X Unit := do
1106  if ((← rdS c.st (·.flags)) &&& 0x0800) != 0 then
1107    if (← get).have_ == 0 then throw Ex.leave
1108    modify fun l => { l with copy := 0 }
1109    xdoWhile
1110      (do
1111        let l ← get
1112        let b ← index8 l.next l.copy.toNat
1113        set { l with len := b.toUInt32, copy := l.copy + 1 }
1114        let s ← ldInflateState c.st
1115        if s.head != none then
1116          let g ← ldGzHeader s.head
1117          if g.name != .null && s.length < g.name_max then
1118            store8 (← g.name.add (s.length.toNat : Int)) b
1119            wrS c.st fun s => { s with length := s.length + 1 })
1120      (do let l ← get; return l.len != 0 && l.copy < l.have_)
1121    if ← hcrcOn c.st then
1122      let l ← get
1123      let v ← crc32 (← rdS c.st (·.check)) l.next l.copy
1124      wrS c.st fun s => { s with check := v }
1125    let l ← get
1126    let nx ← l.next.add (l.copy.toNat : Int)
1127    set { l with have_ := l.have_ - l.copy, next := nx }
1128    if l.len != 0 then throw Ex.leave
1129  else
1130    -- else if (state->head != Z_NULL) state->head->name = Z_NULL;
1131    let s ← ldInflateState c.st
1132    if s.head != none then
1133      let g ← ldGzHeader s.head
1134      stGzHeader s.head { g with name := .null }
1135  -- state->length = 0; state->mode = COMMENT; /* fallthrough */
1136  wrS c.st fun s => { s with length := 0, mode := COMMENT }
1137  inflate_COMMENT c
1138
1139/-- `case EXTRA:` -/
1140def inflate_EXTRA (c : Ctx) : X Unit := do
1141  -- if (state->flags & 0x0400) {
1142  if ((← rdS c.st (·.flags)) &&& 0x0400) != 0 then
1143    -- copy = state->length; if (copy > have) copy = have;
1144    let s ← ldInflateState c.st
1145    let l ← get
1146    let copy := if s.length > l.have_ then l.have_ else s.length
1147    set { l with copy := copy }
1148    -- if (copy) {
1149    if copy != 0 then
1150      -- if (state->head != Z_NULL && state->head->extra != Z_NULL && (len = state->head->extra_len - state->length) < state->head->extra_max) {
1151      if s.head != none then
1152        let g ← ldGzHeader s.head
1153        if g.extra != .null then
1154          let len := g.extra_len - s.length
1155          modify fun l => { l with len := len }
1156          if len < g.extra_max then
1157            -- zmemcpy(state->head->extra + len, next, len + copy > extra_max ? extra_max - len : copy);
1158            let n := if len + copy > g.extra_max then g.extra_max - len else copy
1159            memcpyB (← g.extra.add (len.toNat : Int)) (← get).next n.toNat
1160      -- if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy);
1161      if ← hcrcOn c.st then
1162        let v ← crc32 (← rdS c.st (·.check)) (← get).next copy
1163        wrS c.st fun s => { s with check := v }
1164      -- have -= copy; next += copy; state->length -= copy;
1165      let l ← get
1166      let nx ← l.next.add (copy.toNat : Int)
1167      set { l with have_ := l.have_ - copy, next := nx }
1168      wrS c.st fun s => { s with length := s.length - copy }
1169    -- if (state->length) goto inf_leave;
1170    if (← rdS c.st (·.length)) != 0 then throw Ex.leave
1171  -- state->length = 0; state->mode = NAME; /* fallthrough */
1172  wrS c.st fun s => { s with length := 0, mode := NAME }
1173  inflate_NAME c
1174
1175/-- `case EXLEN:` -/
1176def inflate_EXLEN (c : Ctx) : X Unit := do
1177  let s ← ldInflateState c.st
1178  -- if (state->flags & 0x0400) {
1179  if (s.flags &&& 0x0400) != 0 then
1180    NEEDBITS 16
1181    let l ← get
1182    -- state->length = (unsigned)(hold);
1183    wrS c.st fun s => { s with length := l.hold.toUInt32 }
1184    -- if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold;
1185    let s ← ldInflateState c.st
1186    if s.head != none then
1187      let g ← ldGzHeader s.head
1188      stGzHeader s.head { g with extra_len := l.hold.toUInt32 }
1189    -- if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold);
1190    if ← hcrcOn c.st then CRC2 c
1191    INITBITS
1192  else
1193    -- else if (state->head != Z_NULL) state->head->extra = Z_NULL;
1194    if s.head != none then
1195      let g ← ldGzHeader s.head
1196      stGzHeader s.head { g with extra := .null }
1197  -- state->mode = EXTRA; /* fallthrough */
1198  setMode c.st EXTRA
1199  inflate_EXTRA c
1200
1201/-- `case OS:` -/
1202def inflate_OS (c : Ctx) : X Unit := do
1203  NEEDBITS 16
1204  let l ← get
1205  let s ← ldInflateState c.st
1206  -- if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); }
1207  if s.head != none then
1208    let g ← ldGzHeader s.head
1209    stGzHeader s.head { g with xflags := (l.hold &&& 0xff).toUInt32.toInt32, os := (l.hold >>> 8).toUInt32.toInt32 }
1210  if ← hcrcOn c.st then CRC2 c
1211  INITBITS
1212  setMode c.st EXLEN
1213  inflate_EXLEN c
1214
1215/-- `case TIME:` -/
1216def inflate_TIME (c : Ctx) : X Unit := do
1217  NEEDBITS 32
1218  let l ← get
1219  let s ← ldInflateState c.st
1220  -- if (state->head != Z_NULL) state->head->time = hold;
1221  if s.head != none then
1222    let g ← ldGzHeader s.head
1223    stGzHeader s.head { g with time := l.hold }
1224  -- if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold);
1225  if ← hcrcOn c.st then CRC4 c
1226  INITBITS
1227  setMode c.st OS
1228  inflate_OS c
1229
1230/-- `case FLAGS:` -/
1231def inflate_FLAGS (c : Ctx) : X Unit := do
1232  NEEDBITS 16
1233  let l ← get
1234  -- state->flags = (int)(hold);   (implementation-defined conversion: modulo 2^32)
1235  wrS c.st fun s => { s with flags := l.hold.toUInt32.toInt32 }
1236  let s ← ldInflateState c.st
1237  -- if ((state->flags & 0xff) != Z_DEFLATED) { "unknown compression method"; BAD; break; }
1238  if (s.flags &&& 0xff) != Z_DEFLATED then
1239    badMode c "unknown compression method"
1240    return
1241  -- if (state->flags & 0xe000) { "unknown header flags set"; BAD; break; }
1242  if (s.flags &&& 0xe000) != 0 then
1243    badMode c "unknown header flags set"
1244    return
1245  -- if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1);
1246  if s.head != none then
1247    let g ← ldGzHeader s.head
1248    stGzHeader s.head { g with text := ((l.hold >>> 8) &&& 1).toUInt32.toInt32 }
1249  -- if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold);
1250  if ← hcrcOn c.st then CRC2 c
1251  INITBITS
1252  setMode c.st TIME
1253  inflate_TIME c
1254
1255/-- `case HEAD:` -/
1256def inflate_HEAD (c : Ctx) : X Unit := do
1257  -- if (state->wrap == 0) { state->mode = TYPEDO; break; }
1258  if (← rdS c.st (·.wrap)) == 0 then
1259    setMode c.st TYPEDO
1260    return
1261  NEEDBITS 16
1262  let l ← get
1263  let s ← ldInflateState c.st
1264  -- if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
1265  if (s.wrap &&& 2) != 0 && l.hold == 0x8b1f then
1266    -- if (state->wbits == 0) state->wbits = 15;
1267    if s.wbits == 0 then wrS c.st fun s => { s with wbits := 15 }
1268    -- state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break;
1269    let v ← crc32 0 .null 0
1270    wrS c.st fun s => { s with check := v }
1271    CRC2 c
1272    INITBITS
1273    setMode c.st FLAGS
1274    return
1275  -- if (state->head != Z_NULL) state->head->done = -1;
1276  if s.head != none then
1277    let g ← ldGzHeader s.head
1278    stGzHeader s.head { g with done := -1 }
1279  -- if (!(state->wrap & 1) || ((BITS(8) << 8) + (hold >> 8)) % 31) { "incorrect header check"; BAD; break; }
1280  let b8 ← BITS 8
1281  if (s.wrap &&& 1) == 0 || ((b8 <<< 8).toUInt64 + (l.hold >>> 8)) % 31 != 0 then
1282    badMode c "incorrect header check"
1283    return
1284  -- if (BITS(4) != Z_DEFLATED) { "unknown compression method"; BAD; break; }
1285  if (← BITS 4) != i2u Z_DEFLATED then
1286    badMode c "unknown compression method"
1287    return
1288  DROPBITS 4
1289  -- len = BITS(4) + 8;
1290  let len := (← BITS 4) + 8
1291  modify fun l => { l with len := len }
1292  -- if (len > 15 || (state->wbits != 0 && len > state->wbits)) { "invalid window size"; BAD; break; }
1293  let s ← ldInflateState c.st
1294  if len > 15 || (s.wbits != 0 && len > s.wbits) then
1295    badMode c "invalid window size"
1296    return
1297  -- if (state->wbits == 0) state->wbits = len;
1298  if s.wbits == 0 then wrS c.st fun s => { s with wbits := len }
1299  -- state->dmax = 1U << len; state->flags = 0;
1300  let dm ← shl32 1 len
1301  wrS c.st fun s => { s with dmax := dm, flags := 0 }
1302  -- strm->adler = state->check = adler32(0L, Z_NULL, 0);
1303  let v ← adler32 0 .null 0
1304  wrS c.st fun s => { s with check := v }
1305  wrZ c.strm fun z => { z with adler := v }
1306  -- state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break;
1307  let l ← get
1308  setMode c.st (if (l.hold &&& 0x200) != 0 then DICTID else TYPE)
1309  INITBITS
1310
1311/-- The `switch (state->mode)`: the mode is read from the heap on every trip. `MEM` returns `Z_MEM_ERROR`; `SYNC` and
1312every other value return `Z_STREAM_ERROR`. -/
1313def inflate_dispatch (c : Ctx) : X Unit := do
1314  let m ← rdS c.st (·.mode)
1315  if m == HEAD then inflate_HEAD c
1316  else if m == FLAGS then inflate_FLAGS c
1317  else if m == TIME then inflate_TIME c
1318  else if m == OS then inflate_OS c
1319  else if m == EXLEN then inflate_EXLEN c
1320  else if m == EXTRA then inflate_EXTRA c
1321  else if m == NAME then inflate_NAME c
1322  else if m == COMMENT then inflate_COMMENT c
1323  else if m == HCRC then inflate_HCRC c
1324  else if m == DICTID then inflate_DICTID c
1325  else if m == DICT then inflate_DICT c
1326  else if m == TYPE then inflate_TYPE c
1327  else if m == TYPEDO then inflate_TYPEDO c
1328  else if m == STORED then inflate_STORED c
1329  else if m == COPY_ then inflate_COPY_ c
1330  else if m == COPY then inflate_COPY c
1331  else if m == TABLE then inflate_TABLE c
1332  else if m == LENLENS then inflate_LENLENS c
1333  else if m == CODELENS then inflate_CODELENS c
1334  else if m == LEN_ then inflate_LEN_ c
1335  else if m == LEN then inflate_LEN c
1336  else if m == LENEXT then inflate_LENEXT c
1337  else if m == DIST then inflate_DIST c
1338  else if m == DISTEXT then inflate_DISTEXT c
1339  else if m == MATCH then inflate_MATCH c
1340  else if m == LIT then inflate_LIT c
1341  else if m == CHECK then inflate_CHECK c
1342  else if m == LENGTH then inflate_LENGTH c
1343  else if m == DONE then inflate_DONE c
1344  else if m == BAD then
1345    -- case BAD: ret = Z_DATA_ERROR; goto inf_leave;
1346    modify fun l => { l with ret := Z_DATA_ERROR }
1347    throw Ex.leave
1348  else if m == MEM then throw (Ex.ret Z_MEM_ERROR)
1349  else throw (Ex.ret Z_STREAM_ERROR)
1350
1351/-- Everything of `inflate()` from `LOAD()` to the end of `for (;;) switch`. -/
1352def inflate_run (c : Ctx) : X Unit := do
1353  -- if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
1354  if (← rdS c.st (·.mode)) == TYPE then setMode c.st TYPEDO
1355  LOAD c.strm c.st
1356  -- in = have; out = left; ret = Z_OK;
1357  modify fun l => { l with in_ := l.have_, out_ := l.left, ret := Z_OK }
1358  -- for (;;) switch (state->mode) { ... }
1359  xwhile (pure true) (inflate_dispatch c)
1360
1361/-- `inf_leave:` and what follows it (`RESTORE()` .. `return ret`), with the registers `l` at the `goto`. -/
1362def inflate_leave (c : Ctx) (l : IL) : M Int32 := do
1363  -- RESTORE();
1364  wrZ c.strm fun z => { z with next_out := l.put, avail_out := l.left, next_in := l.next, avail_in := l.have_ }
1365  wrS c.st fun s => { s with hold := l.hold, bits := l.bits }
1366  let z ← ldZStream c.strm
1367  let s ← ldInflateState c.st
1368  -- if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH)))
1369  --     if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; }
1370  if s.wsize != 0 || (l.out_ != z.avail_out && s.mode < BAD && (s.mode < CHECK || c.flush != Z_FINISH)) then
1371    if (← updatewindow c.strm z.next_out (l.out_ - z.avail_out)) != 0 then
1372      setMode c.st MEM
1373      return Z_MEM_ERROR
1374  -- in -= strm->avail_in; out -= strm->avail_out;
1375  let in_ := l.in_ - z.avail_in
1376  let out_ := l.out_ - z.avail_out
1377  -- strm->total_in += in; strm->total_out += out; state->total += out;
1378  wrZ c.strm fun z => { z with total_in := z.total_in + in_.toUInt64, total_out := z.total_out + out_.toUInt64 }
1379  wrS c.st fun s => { s with total := s.total + out_.toUInt64 }
1380  -- if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE_CHECK(state->check, strm->next_out - out, out);
1381  let s ← ldInflateState c.st
1382  if (s.wrap &&& 4) != 0 && out_ != 0 then
1383    let p ← z.next_out.add (-(out_.toNat : Int))
1384    let v ← UPDATE_CHECK c.st s.check p out_
1385    wrS c.st fun s => { s with check := v }
1386    wrZ c.strm fun z => { z with adler := v }
1387  -- strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) +
1388  --                   (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
1389  let s ← ldInflateState c.st
1390  let dt ← chkI32 ((u2i s.bits).toInt + (if s.last != 0 then 64 else 0) + (if s.mode == TYPE then 128 else 0) +
1391    (if s.mode == LEN_ || s.mode == COPY_ then 256 else 0))
1392  wrZ c.strm fun z => { z with data_type := dt }
1393  -- if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR;
1394  let mut ret := l.ret
1395  if ((in_ == 0 && out_ == 0) || c.flush == Z_FINISH) && ret == Z_OK then ret := Z_BUF_ERROR
1396  return ret
1397
1398/-- `int ZEXPORT inflate(z_streamp strm, int flush)` -/
1399def inflate (strm : ZStreamPtr) (flush : Int32) : M Int32 := do
1400  -- unsigned char hbuf[4];
1401  let hbuf ← allocLocalB 4
1402  let r ← (do
1403    -- if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR;
1404    if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1405    let z ← ldZStream strm
1406    if z.next_out == .null || (z.next_in == .null && z.avail_in != 0) then return Z_STREAM_ERROR
1407    -- state = (struct inflate_state FAR *)strm->state;
1408    let st ← castInflateState z.state
1409    let c : Ctx := { strm, st, hbuf, flush }
1410    let (r, l) ← StateT.run (ExceptT.run (inflate_run c)) IL.init
1411    match r with
1412    | .error (.ret v) => return v
1413    | _ => inflate_leave c l)
1414  freeB hbuf
1415  return r
1416
1417/-- `int ZEXPORT inflateEnd(z_streamp strm)` -/
1418def inflateEnd (strm : ZStreamPtr) : M Int32 := do
1419  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1420  let z ← ldZStream strm
1421  let st ← castInflateState z.state
1422  -- if (state->window != Z_NULL) ZFREE(strm, state->window);
1423  let s ← ldInflateState st
1424  if s.window != .null then ZFREEB strm s.window
1425  -- ZFREE(strm, strm->state); strm->state = Z_NULL;
1426  ZFREES strm st
1427  wrZ strm fun z => { z with state := none }
1428  return Z_OK
1429
1430/-- `int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary, uInt *dictLength)`.
1431`dictLength` is the value of `*dictLength` (`none` for `NULL`); the second result is `*dictLength` afterwards. -/
1432def inflateGetDictionary (strm : ZStreamPtr) (dictionary : BPtr) (dictLength : Option UInt32) :
1433    M (Int32 × Option UInt32) := do
1434  if (← inflateStateCheck strm) != 0 then return (Z_STREAM_ERROR, dictLength)
1435  let z ← ldZStream strm
1436  let st ← castInflateState z.state
1437  let s ← ldInflateState st
1438  -- if (state->whave && dictionary != Z_NULL) {
1439  if s.whave != 0 && dictionary != .null then
1440    -- zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext);
1441    memcpyB dictionary (← s.window.add (s.wnext.toNat : Int)) (s.whave - s.wnext).toNat
1442    -- zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext);
1443    let d1 ← dictionary.add (s.whave.toNat : Int)
1444    let d2 ← d1.add (-(s.wnext.toNat : Int))
1445    memcpyB d2 s.window s.wnext.toNat
1446  -- if (dictLength != Z_NULL) *dictLength = state->whave;
1447  match dictLength with
1448  | some _ => return (Z_OK, some s.whave)
1449  | none => return (Z_OK, none)
1450
1451/-- `int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary, uInt dictLength)` -/
1452def inflateSetDictionary (strm : ZStreamPtr) (dictionary : BPtr) (dictLength : UInt32) : M Int32 := do
1453  -- if (inflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR;
1454  if (← inflateStateCheck strm) != 0 || dictionary == .null then return Z_STREAM_ERROR
1455  let z ← ldZStream strm
1456  let st ← castInflateState z.state
1457  let s ← ldInflateState st
1458  -- if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR;
1459  if s.wrap != 0 && s.mode != DICT then return Z_STREAM_ERROR
1460  -- if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; }
1461  if s.mode == DICT then
1462    let dictid ← adler32 0 .null 0
1463    let dictid ← adler32 dictid dictionary dictLength
1464    if dictid != s.check then return Z_DATA_ERROR
1465  -- ret = updatewindow(strm, dictionary + dictLength, dictLength);
1466  let ret ← updatewindow strm (← dictionary.add (dictLength.toNat : Int)) dictLength
1467  -- if (ret) { state->mode = MEM; return Z_MEM_ERROR; }
1468  if ret != 0 then
1469    setMode st MEM
1470    return Z_MEM_ERROR
1471  -- state->havedict = 1;
1472  wrS st fun s => { s with havedict := 1 }
1473  return Z_OK
1474
1475/-- `int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head)` -/
1476def inflateGetHeader (strm : ZStreamPtr) (head : GzHeaderPtr) : M Int32 := do
1477  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1478  let z ← ldZStream strm
1479  let st ← castInflateState z.state
1480  -- if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
1481  if ((← rdS st (·.wrap)) &&& 2) == 0 then return Z_STREAM_ERROR
1482  -- state->head = head; head->done = 0;
1483  wrS st fun s => { s with head := head }
1484  let g ← ldGzHeader head
1485  stGzHeader head { g with done := 0 }
1486  return Z_OK
1487
1488/-- `local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf, unsigned len)`.
1489`have` is the value of `*have`; the result is (return value, `*have` afterwards). -/
1490def syncsearch (have_ : UInt32) (buf : BPtr) (len : UInt32) : M (UInt32 × UInt32) := do
1491  -- got = *have; next = 0;
1492  let (next, got) ← cwhile (σ := UInt32 × UInt32)
1493    -- while (next < len && got < 4) {
1494    (fun (next, got) => pure (next < len && got < 4, (next, got)))
1495    (fun (next, got) => do
1496      let b ← index8 buf next.toNat
1497      -- if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got;
1498      let got := if b.toNat == (if got < 2 then 0 else 0xff) then got + 1 else if b != 0 then 0 else 4 - got
1499      -- next++;
1500      pure (next + 1, got))
1501    (0, have_)
1502  -- *have = got; return next;
1503  return (next, got)
1504
1505/-- `int ZEXPORT inflateSync(z_streamp strm)` -/
1506def inflateSync (strm : ZStreamPtr) : M Int32 := do
1507  -- unsigned char buf[4];
1508  let buf ← allocLocalB 4
1509  let r ← (do
1510    if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1511    let z ← ldZStream strm
1512    let st ← castInflateState z.state
1513    let s ← ldInflateState st
1514    -- if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
1515    if z.avail_in == 0 && s.bits < 8 then return Z_BUF_ERROR
1516    -- if (state->mode != SYNC) {
1517    if s.mode != SYNC then
1518      -- state->mode = SYNC; state->hold >>= state->bits & 7; state->bits -= state->bits & 7;
1519      let h ← shr64 s.hold (s.bits &&& 7)
1520      wrS st fun s => { s with mode := SYNC, hold := h, bits := s.bits - (s.bits &&& 7) }
1521      -- len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; }
1522      let len ← cwhile (σ := UInt32)
1523        (fun len => do return ((← rdS st (·.bits)) >= 8, len))
1524        (fun len => do
1525          let s ← ldInflateState st
1526          store8 (← buf.add (len.toNat : Int)) s.hold.toUInt8
1527          wrS st fun s => { s with hold := s.hold >>> 8, bits := s.bits - 8 }
1528          pure (len + 1))
1529        0
1530      -- state->have = 0; syncsearch(&(state->have), buf, len);
1531      wrS st fun s => { s with «have» := 0 }
1532      let (_, hv) ← syncsearch 0 buf len
1533      wrS st fun s => { s with «have» := hv }
1534    -- len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
1535    let z ← ldZStream strm
1536    let (len, hv) ← syncsearch (← rdS st (·.«have»)) z.next_in z.avail_in
1537    wrS st fun s => { s with «have» := hv }
1538    -- strm->avail_in -= len; strm->next_in += len; strm->total_in += len;
1539    let ni ← z.next_in.add (len.toNat : Int)
1540    wrZ strm fun z => { z with avail_in := z.avail_in - len, next_in := ni, total_in := z.total_in + len.toUInt64 }
1541    -- if (state->have != 4) return Z_DATA_ERROR;
1542    if (← rdS st (·.«have»)) != 4 then return Z_DATA_ERROR
1543    -- flags = state->flags; in = strm->total_in; out = strm->total_out;
1544    let flags ← rdS st (·.flags)
1545    let z ← ldZStream strm
1546    let in_ := z.total_in
1547    let out_ := z.total_out
1548    -- inflateReset(strm);
1549    let _ ← inflateReset strm
1550    -- strm->total_in = in; strm->total_out = out; state->flags = flags;
1551    wrZ strm fun z => { z with total_in := in_, total_out := out_ }
1552    wrS st fun s => { s with flags := flags }
1553    -- if (flags == -1) state->wrap = 0; else state->wrap &= ~4;
1554    if flags == -1 then wrS st fun s => { s with wrap := 0 }
1555    else wrS st fun s => { s with wrap := s.wrap &&& ~~~4 }
1556    -- if (state->wbits == 0) {
1557    let s ← ldInflateState st
1558    if s.wbits == 0 then
1559      if s.window != .null then
1560        ZFREEB strm s.window
1561        wrS st fun s => { s with window := .null }
1562      wrS st fun s => { s with wbits := 15 }
1563    -- state->mode = TYPE; return Z_OK;
1564    setMode st TYPE
1565    return Z_OK)
1566  freeB buf
1567  return r
1568
1569/-- `int ZEXPORT inflateSyncPoint(z_streamp strm)` -/
1570def inflateSyncPoint (strm : ZStreamPtr) : M Int32 := do
1571  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1572  let z ← ldZStream strm
1573  let st ← castInflateState z.state
1574  let s ← ldInflateState st
1575  -- return state->mode == STORED && state->bits == 0;
1576  return if s.mode == STORED && s.bits == 0 then 1 else 0
1577
1578/-- `int ZEXPORT inflateCopy(z_streamp dest, z_streamp source)` -/
1579def inflateCopy (dest source : ZStreamPtr) : M Int32 := do
1580  -- if (dest == Z_NULL) return Z_STREAM_ERROR;
1581  if dest == none then return Z_STREAM_ERROR
1582  -- if (inflateStateCheck(source)) { dest->state = Z_NULL; return Z_STREAM_ERROR; }
1583  if (← inflateStateCheck source) != 0 then
1584    wrZ dest fun z => { z with state := none }
1585    return Z_STREAM_ERROR
1586  let zs ← ldZStream source
1587  let state ← castInflateState zs.state
1588  -- copy = ZALLOC(source, 1, sizeof(struct inflate_state));
1589  let copy ← ZALLOCS source
1590  -- if (copy == Z_NULL) { dest->state = Z_NULL; return Z_MEM_ERROR; }
1591  if copy == none then
1592    wrZ dest fun z => { z with state := none }
1593    return Z_MEM_ERROR
1594  -- zmemzero(copy, sizeof(struct inflate_state));
1595  stInflateState copy (InflateState.zeroed)
1596  -- window = Z_NULL;
1597  let mut window : BPtr := .null
1598  let s ← ldInflateState state
1599  -- if (state->window != Z_NULL) {
1600  if s.window != .null then
1601    window ← ZALLOCB source (← shl32 1 s.wbits) 1
1602    -- if (window == Z_NULL) { ZFREE(source, copy); dest->state = Z_NULL; return Z_MEM_ERROR; }
1603    if window == .null then
1604      ZFREES source copy
1605      wrZ dest fun z => { z with state := none }
1606      return Z_MEM_ERROR
1607  -- zmemcpy(dest, source, sizeof(z_stream));   (a whole-struct copy; the same object is overlapping)
1608  copyZStream dest source
1609  -- zmemcpy(copy, state, sizeof(struct inflate_state));
1610  copyInflateState copy state
1611  -- copy->strm = dest;
1612  wrS copy fun s => { s with strm := dest }
1613  -- if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) {
1614  let s ← ldInflateState state
1615  let hi ← (← (codesP state).add 1444).add (-1)
1616  if (← Ptr.le (codesP state) s.lencode) && (← Ptr.le s.lencode hi) then
1617    -- copy->lencode = copy->codes + (state->lencode - state->codes);
1618    let d1 ← Ptr.diff s.lencode (codesP state)
1619    let lc ← (codesP copy).add d1.toInt
1620    -- copy->distcode = copy->codes + (state->distcode - state->codes);
1621    let d2 ← Ptr.diff s.distcode (codesP state)
1622    let dc ← (codesP copy).add d2.toInt
1623    wrS copy fun s => { s with lencode := lc, distcode := dc }
1624  -- copy->next = copy->codes + (state->next - state->codes);
1625  let d3 ← Ptr.diff s.next (codesP state)
1626  let nx ← (codesP copy).add d3.toInt
1627  wrS copy fun s => { s with next := nx }
1628  -- if (window != Z_NULL) zmemcpy(window, state->window, state->whave);
1629  if window != .null then memcpyB window s.window s.whave.toNat
1630  -- copy->window = window; dest->state = (struct internal_state FAR *)copy;
1631  wrS copy fun s => { s with window := window }
1632  wrZ dest fun z => { z with state := StateRef.ofInflateState copy }
1633  return Z_OK
1634
1635/-- `int ZEXPORT inflateUndermine(z_streamp strm, int subvert)` (`INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR` undefined) -/
1636def inflateUndermine (strm : ZStreamPtr) (_subvert : Int32) : M Int32 := do
1637  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1638  let z ← ldZStream strm
1639  let st ← castInflateState z.state
1640  -- (void)subvert; state->sane = 1; return Z_DATA_ERROR;
1641  wrS st fun s => { s with sane := 1 }
1642  return Z_DATA_ERROR
1643
1644/-- `int ZEXPORT inflateValidate(z_streamp strm, int check)` -/
1645def inflateValidate (strm : ZStreamPtr) (check : Int32) : M Int32 := do
1646  if (← inflateStateCheck strm) != 0 then return Z_STREAM_ERROR
1647  let z ← ldZStream strm
1648  let st ← castInflateState z.state
1649  let s ← ldInflateState st
1650  -- if (check && state->wrap) state->wrap |= 4; else state->wrap &= ~4;
1651  let wrap := if check != 0 && s.wrap != 0 then s.wrap ||| 4 else s.wrap &&& ~~~4
1652  -- if (check && state->reqwrap) state->reqwrap |= 4; else state->reqwrap &= ~4;
1653  let reqwrap := if check != 0 && s.reqwrap != 0 then s.reqwrap ||| 4 else s.reqwrap &&& ~~~4
1654  wrS st fun s => { s with wrap := wrap, reqwrap := reqwrap }
1655  return Z_OK
1656
1657/-- `long ZEXPORT inflateMark(z_streamp strm)` -/
1658def inflateMark (strm : ZStreamPtr) : M Int64 := do
1659  -- if (inflateStateCheck(strm)) return -(1L << 16);
1660  if (← inflateStateCheck strm) != 0 then return -((1 : Int64) <<< 16)
1661  let z ← ldZStream strm
1662  let st ← castInflateState z.state
1663  let s ← ldInflateState st
1664  -- (long)(((unsigned long)((long)state->back)) << 16)
1665  let hi : Int64 := ((s.back.toInt64.toUInt64) <<< 16).toInt64
1666  -- state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)   (type unsigned)
1667  let lo : UInt32 := if s.mode == COPY then s.length else if s.mode == MATCH then s.was - s.length else 0
1668  chkI64 (hi.toInt + lo.toNat)
1669
1670/-- `unsigned long ZEXPORT inflateCodesUsed(z_streamp strm)` -/
1671def inflateCodesUsed (strm : ZStreamPtr) : M UInt64 := do
1672  -- if (inflateStateCheck(strm)) return (unsigned long)-1;
1673  if (← inflateStateCheck strm) != 0 then return 0xffffffffffffffff
1674  let z ← ldZStream strm
1675  let st ← castInflateState z.state
1676  let s ← ldInflateState st
1677  -- return (unsigned long)(state->next - state->codes);
1678  let d ← Ptr.diff s.next (codesP st)
1679  return d.toUInt64
1680
1681end Zlib.Inflate
ZLIB × LEAN

全局目录

当前位置inflate.c.lean