REFERENCE / ZLIB × LEAN
infback.c.lean
Source snapshot ·
b51d2ae63c4ff085 · 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.Zlib.«inflate.c»
2
3/-!
4# infback.c — faithful translation
5
6Source: `infback.c` of the verified source, default x86_64 Linux build (same configuration as `inflate.c.lean`; read its
7header first: the registers, the monad `X`, `goto inf_leave` as `throw Ex.leave`, the loops).
8
9## The call-backs
10
11`inflateBack` takes the caller's functions as parameters (they are caller code, not library code):
12
13* `in_func`: `unsigned (*)(void *in_desc, z_const unsigned char **buf)` is `InCb`. The C passes `&next`, the address of
14 the local `next`. A pointer to a scalar is passed by value (decision D3 of the notes): the call-back receives the
15 current value of `next` and returns `(count, new value of *buf)`. A call-back that keeps the address and writes
16 through it after it returned is not modelled.
17* `out_func`: `int (*)(void *out_desc, unsigned char *buf, unsigned len)` is `OutCb`.
18
19Both run on the shared heap, so they can read and write any block. `inflateBack` makes no assumption about them; a
20theorem about it has to state what it needs (`docs/proof/callbacks.md`).
21
22## Other decisions
23
24* `inflateBackInit_` does **not** zero the state: the record is `allocInflateState`, arbitrary integers and null
25 pointers, and only the fields the C writes are written.
26* `ret` is not initialised in the C before `for (;;)`; it is set before every `goto inf_leave`. It starts as `0` here.
27-/
28
29namespace Zlib.Infback
30open C
31open Zlib.Crc32 (crc32)
32open Zlib.Inffast (inflate_fast)
33open Zlib.Inftrees (inflate_table inflate_fixed)
34open Zlib.Inflate (X Ex IL Stop xwhile xwhileBrk xdoWhile xloopBrk shl32 shr32 shl64 u2i i2u chkI32 BITS DROPBITS BYTEBITS
35 INITBITS LOAD RESTORE rdS wrS rdZ wrZ lensP workP codesP orderAt setMsg setMode ZALLOCS ZFREES)
36
37/-- `in_func`: `unsigned (*)(void FAR *, z_const unsigned char FAR * FAR *)`; see the file comment. -/
38abbrev InCb := BPtr → BPtr → M (UInt32 × BPtr)
39/-- `out_func`: `int (*)(void FAR *, unsigned char FAR *, unsigned)` -/
40abbrev OutCb := BPtr → BPtr → UInt32 → M Int32
41
42/-- What `inflateBack()` and its macros share. -/
43structure BCtx where
44 strm : ZStreamPtr
45 st : InflateStatePtr
46 inCb : InCb
47 inDesc : BPtr
48 outCb : OutCb
49 outDesc : BPtr
50
51/-- `int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits, unsigned char FAR *window, const char *version,
52int stream_size)` -/
53def inflateBackInit_ (strm : ZStreamPtr) (windowBits : Int32) (window : BPtr) (version : BPtr) (stream_size : Int32) :
54 M Int32 := do
55 -- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR;
56 if version == .null then return Z_VERSION_ERROR
57 if (← index8 version 0) != 49 then return Z_VERSION_ERROR
58 if stream_size != 112 then return Z_VERSION_ERROR
59 -- if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR;
60 if strm == none || window == .null || windowBits < 8 || windowBits > 15 then return Z_STREAM_ERROR
61 -- strm->msg = Z_NULL;
62 wrZ strm fun z => { z with msg := .null }
63 -- if (strm->zalloc == (alloc_func)0) { strm->zalloc = zcalloc; strm->opaque = (voidpf)0; }
64 if (← rdZ strm (·.zalloc)) == .null then
65 wrZ strm fun z => { z with zalloc := .fn "zcalloc", «opaque» := .null }
66 -- if (strm->zfree == (free_func)0) strm->zfree = zcfree;
67 if (← rdZ strm (·.zfree)) == .null then
68 wrZ strm fun z => { z with zfree := .fn "zcfree" }
69 -- state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); (not zeroed)
70 let state ← ZALLOCS strm
71 -- if (state == Z_NULL) return Z_MEM_ERROR;
72 if state == none then return Z_MEM_ERROR
73 -- strm->state = (struct internal_state FAR *)state;
74 wrZ strm fun z => { z with state := StateRef.ofInflateState state }
75 -- state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits;
76 let ws ← shl32 1 (i2u windowBits)
77 -- state->window = window; state->wnext = 0; state->whave = 0; state->sane = 1;
78 wrS state fun s => { s with
79 dmax := 32768, wbits := i2u windowBits, wsize := ws, window := window, wnext := 0, whave := 0, sane := 1 }
80 return Z_OK
81
82/-! ## The macros of `infback.c` that differ from `inflate.c` -/
83
84/-- `PULL()`: calls the caller's `in` when `have == 0`; `goto inf_leave` with `next = NULL`, `ret = Z_BUF_ERROR` if it
85returns 0. -/
86def PULL (c : BCtx) : X Unit := do
87 let l ← get
88 if l.have_ == 0 then
89 -- have = in(in_desc, &next);
90 let (h, nx) ← c.inCb c.inDesc l.next
91 set { l with have_ := h, next := nx }
92 if h == 0 then
93 -- next = Z_NULL; ret = Z_BUF_ERROR; goto inf_leave;
94 set { l with have_ := h, next := .null, ret := Z_BUF_ERROR }
95 throw Ex.leave
96
97/-- `PULLBYTE()` -/
98def PULLBYTE (c : BCtx) : X Unit := do
99 PULL c
100 let l ← get
101 -- have--; hold += (unsigned long)(*next++) << bits; bits += 8;
102 let b ← load8 l.next
103 let nx ← l.next.add 1
104 let sh ← shl64 b.toUInt64 l.bits
105 set { l with have_ := l.have_ - 1, next := nx, hold := l.hold + sh, bits := l.bits + 8 }
106
107/-- `NEEDBITS(n)` -/
108def NEEDBITS (c : BCtx) (n : UInt32) : X Unit :=
109 xwhile (do return (← get).bits < n) (PULLBYTE c)
110
111/-- `ROOM()`: when the window is full, hand it to `out`. -/
112def ROOM (c : BCtx) : X Unit := do
113 let l ← get
114 if l.left == 0 then
115 -- put = state->window; left = state->wsize; state->whave = left;
116 let s ← ldInflateState c.st
117 set { l with put := s.window, left := s.wsize }
118 wrS c.st fun s => { s with whave := s.wsize }
119 -- if (out(out_desc, put, left)) { ret = Z_BUF_ERROR; goto inf_leave; }
120 if (← c.outCb c.outDesc s.window s.wsize) != 0 then
121 modify fun l => { l with ret := Z_BUF_ERROR }
122 throw Ex.leave
123
124/-- `strm->msg = "..."; state->mode = BAD;` -/
125def badMode (c : BCtx) (msg : String) : M Unit := do
126 setMsg c.strm msg
127 setMode c.st BAD
128
129/-- `for (;;) { here = TABLE[BITS(bitsOfTable)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); }` -/
130def lookup1 (c : BCtx) (dist : Bool) : X Unit :=
131 xloopBrk (do
132 let s ← ldInflateState c.st
133 let tab := if dist then s.distcode else s.lencode
134 let nb := if dist then s.distbits else s.lenbits
135 let b ← BITS nb
136 let here ← Ptr.index tab (b.toNat : Int)
137 modify fun l => { l with here := here }
138 if here.bits.toUInt32 <= (← get).bits then return true
139 PULLBYTE c
140 return false)
141
142/-- `for (;;) { here = TABLE[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); }` -/
143def lookup2 (c : BCtx) (dist : Bool) : X Unit :=
144 xloopBrk (do
145 let s ← ldInflateState c.st
146 let tab := if dist then s.distcode else s.lencode
147 let last := (← get).last
148 let b ← BITS (last.bits.toUInt32 + last.op.toUInt32)
149 let sh ← shr32 b last.bits.toUInt32
150 let here ← Ptr.index tab ((last.val.toUInt32 + sh).toNat : Int)
151 modify fun l => { l with here := here }
152 if (last.bits.toUInt32 + here.bits.toUInt32) <= (← get).bits then return true
153 PULLBYTE c
154 return false)
155
156/-! ## The modes -/
157
158/-- `case LEN:` -/
159def back_LEN (c : BCtx) : X Unit := do
160 let l ← get
161 -- if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, state->wsize); LOAD(); break; }
162 if l.have_ >= 6 && l.left >= 258 then
163 RESTORE c.strm c.st
164 inflate_fast c.strm (← rdS c.st (·.wsize))
165 LOAD c.strm c.st
166 return
167 lookup1 c false
168 let here := (← get).here
169 -- if (here.op && (here.op & 0xf0) == 0) {
170 if here.op != 0 && (here.op &&& 0xf0) == 0 then
171 modify fun l => { l with last := here }
172 lookup2 c false
173 DROPBITS (← get).last.bits.toUInt32
174 -- DROPBITS(here.bits); state->length = (unsigned)here.val;
175 let here := (← get).here
176 DROPBITS here.bits.toUInt32
177 wrS c.st fun s => { s with length := here.val.toUInt32 }
178 -- if (here.op == 0) { ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; }
179 if here.op == 0 then
180 ROOM c
181 let l ← get
182 store8 l.put (← ldInflateState c.st).length.toUInt8
183 let p ← l.put.add 1
184 set { l with put := p, left := l.left - 1 }
185 setMode c.st LEN
186 return
187 -- if (here.op & 32) { state->mode = TYPE; break; }
188 if (here.op &&& 32) != 0 then
189 setMode c.st TYPE
190 return
191 -- if (here.op & 64) { "invalid literal/length code"; BAD; break; }
192 if (here.op &&& 64) != 0 then
193 badMode c "invalid literal/length code"
194 return
195 -- state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS; length += BITS(extra); DROPBITS(extra); }
196 wrS c.st fun s => { s with extra := here.op.toUInt32 &&& 15 }
197 let ex := here.op.toUInt32 &&& 15
198 if ex != 0 then
199 NEEDBITS c ex
200 let b ← BITS ex
201 wrS c.st fun s => { s with length := s.length + b }
202 DROPBITS ex
203 -- get distance code
204 lookup1 c true
205 let here := (← get).here
206 if (here.op &&& 0xf0) == 0 then
207 modify fun l => { l with last := here }
208 lookup2 c true
209 DROPBITS (← get).last.bits.toUInt32
210 let here := (← get).here
211 DROPBITS here.bits.toUInt32
212 -- if (here.op & 64) { "invalid distance code"; BAD; break; }
213 if (here.op &&& 64) != 0 then
214 badMode c "invalid distance code"
215 return
216 -- state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15;
217 wrS c.st fun s => { s with offset := here.val.toUInt32, extra := here.op.toUInt32 &&& 15 }
218 let ex := here.op.toUInt32 &&& 15
219 if ex != 0 then
220 NEEDBITS c ex
221 let b ← BITS ex
222 wrS c.st fun s => { s with offset := s.offset + b }
223 DROPBITS ex
224 -- if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { "invalid distance too far back"; BAD; break; }
225 let s ← ldInflateState c.st
226 let l ← get
227 if s.offset > s.wsize - (if s.whave < s.wsize then l.left else 0) then
228 badMode c "invalid distance too far back"
229 return
230 -- do { ROOM(); copy = state->wsize - state->offset; ...; do { *put++ = *from++; } while (--copy); } while (state->length != 0);
231 xdoWhile
232 (do
233 ROOM c
234 let s ← ldInflateState c.st
235 let l ← get
236 -- copy = state->wsize - state->offset;
237 let copy := s.wsize - s.offset
238 -- if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; }
239 let (from_, copy) ← if copy < l.left then do
240 pure (← l.put.add (copy.toNat : Int), l.left - copy)
241 else do
242 pure (← l.put.add (-(s.offset.toNat : Int)), l.left)
243 -- if (copy > state->length) copy = state->length;
244 let copy := if copy > s.length then s.length else copy
245 -- state->length -= copy; left -= copy;
246 wrS c.st fun s => { s with length := s.length - copy }
247 set { l with copy := copy, from_ := from_, left := l.left - copy }
248 xdoWhile
249 (do
250 let l ← get
251 let b ← load8 l.from_
252 store8 l.put b
253 let p ← l.put.add 1
254 let f ← l.from_.add 1
255 set { l with put := p, from_ := f })
256 (do
257 let l ← get
258 let n := l.copy - 1
259 set { l with copy := n }
260 return n != 0))
261 (do return (← rdS c.st (·.length)) != 0)
262
263/-- `case TABLE:` (falls through into `LEN`) -/
264def back_TABLE (c : BCtx) : X Unit := do
265 NEEDBITS c 14
266 let b ← BITS 5
267 wrS c.st fun s => { s with nlen := b + 257 }
268 DROPBITS 5
269 let b ← BITS 5
270 wrS c.st fun s => { s with ndist := b + 1 }
271 DROPBITS 5
272 let b ← BITS 4
273 wrS c.st fun s => { s with ncode := b + 4 }
274 DROPBITS 4
275 -- if (state->nlen > 286 || state->ndist > 30) { "too many length or distance symbols"; BAD; break; }
276 let s ← ldInflateState c.st
277 if s.nlen > 286 || s.ndist > 30 then
278 badMode c "too many length or distance symbols"
279 return
280 -- state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); lens[order[have++]] = BITS(3); DROPBITS(3); }
281 wrS c.st fun s => { s with «have» := 0 }
282 xwhile
283 (do let s ← ldInflateState c.st; return s.«have» < s.ncode)
284 (do
285 NEEDBITS c 3
286 let s ← ldInflateState c.st
287 wrS c.st fun s => { s with «have» := s.«have» + 1 }
288 let o ← orderAt s.«have»
289 let b ← BITS 3
290 Ptr.store (← (lensP c.st).add (o.toNat : Int)) b.toUInt16
291 DROPBITS 3)
292 xwhile
293 (do let s ← ldInflateState c.st; return s.«have» < 19)
294 (do
295 let s ← ldInflateState c.st
296 wrS c.st fun s => { s with «have» := s.«have» + 1 }
297 let o ← orderAt s.«have»
298 Ptr.store (← (lensP c.st).add (o.toNat : Int)) (0 : UInt16))
299 -- state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7;
300 wrS c.st fun s => { s with next := codesP c.st, lencode := codesP c.st, lenbits := 7 }
301 let s ← ldInflateState c.st
302 let (r, nx, lb) ← inflate_table CODES (lensP c.st) 19 s.next s.lenbits (workP c.st)
303 wrS c.st fun s => { s with next := nx, lenbits := lb }
304 modify fun l => { l with ret := r }
305 if r != 0 then
306 badMode c "invalid code lengths set"
307 return
308 -- state->have = 0; while (state->have < state->nlen + state->ndist) { ... }
309 wrS c.st fun s => { s with «have» := 0 }
310 xwhileBrk
311 (do let s ← ldInflateState c.st; return s.«have» < s.nlen + s.ndist)
312 (do
313 lookup1 c false
314 let here := (← get).here
315 if here.val < 16 then
316 DROPBITS here.bits.toUInt32
317 let s ← ldInflateState c.st
318 Ptr.store (← (lensP c.st).add (s.«have».toNat : Int)) here.val
319 wrS c.st fun s => { s with «have» := s.«have» + 1 }
320 return false
321 else
322 if here.val == 16 then
323 NEEDBITS c (here.bits.toUInt32 + 2)
324 DROPBITS here.bits.toUInt32
325 let s ← ldInflateState c.st
326 if s.«have» == 0 then
327 badMode c "invalid bit length repeat"
328 return true
329 -- len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2);
330 let v ← Ptr.index (lensP c.st) ((s.«have» - 1).toNat : Int)
331 let b ← BITS 2
332 modify fun l => { l with len := v.toUInt32, copy := 3 + b }
333 DROPBITS 2
334 else if here.val == 17 then
335 NEEDBITS c (here.bits.toUInt32 + 3)
336 DROPBITS here.bits.toUInt32
337 let b ← BITS 3
338 modify fun l => { l with len := 0, copy := 3 + b }
339 DROPBITS 3
340 else
341 NEEDBITS c (here.bits.toUInt32 + 7)
342 DROPBITS here.bits.toUInt32
343 let b ← BITS 7
344 modify fun l => { l with len := 0, copy := 11 + b }
345 DROPBITS 7
346 let s ← ldInflateState c.st
347 if s.«have» + (← get).copy > s.nlen + s.ndist then
348 badMode c "invalid bit length repeat"
349 return true
350 xwhile
351 (do
352 let l ← get
353 set { l with copy := l.copy - 1 }
354 return l.copy != 0)
355 (do
356 let s ← ldInflateState c.st
357 Ptr.store (← (lensP c.st).add (s.«have».toNat : Int)) (← get).len.toUInt16
358 wrS c.st fun s => { s with «have» := s.«have» + 1 })
359 return false)
360 -- if (state->mode == BAD) break;
361 if (← rdS c.st (·.mode)) == BAD then return
362 -- if (state->lens[256] == 0) { "invalid code -- missing end-of-block"; BAD; break; }
363 if (← Ptr.index (lensP c.st) 256) == (0 : UInt16) then
364 badMode c "invalid code -- missing end-of-block"
365 return
366 wrS c.st fun s => { s with next := codesP c.st, lencode := codesP c.st, lenbits := 9 }
367 let s ← ldInflateState c.st
368 let (r, nx, lb) ← inflate_table LENS (lensP c.st) s.nlen s.next s.lenbits (workP c.st)
369 wrS c.st fun s => { s with next := nx, lenbits := lb }
370 modify fun l => { l with ret := r }
371 if r != 0 then
372 badMode c "invalid literal/lengths set"
373 return
374 wrS c.st fun s => { s with distcode := s.next, distbits := 6 }
375 let s ← ldInflateState c.st
376 let (r, nx, db) ← inflate_table DISTS (← (lensP c.st).add (s.nlen.toNat : Int)) s.ndist s.next s.distbits (workP c.st)
377 wrS c.st fun s => { s with next := nx, distbits := db }
378 modify fun l => { l with ret := r }
379 if r != 0 then
380 badMode c "invalid distances set"
381 return
382 -- state->mode = LEN; /* fallthrough */
383 setMode c.st LEN
384 back_LEN c
385
386/-- `case STORED:` -/
387def back_STORED (c : BCtx) : X Unit := do
388 BYTEBITS
389 NEEDBITS c 32
390 let l ← get
391 if (l.hold &&& (0xffff : UInt64)) != ((l.hold >>> 16) ^^^ (0xffff : UInt64)) then
392 badMode c "invalid stored block lengths"
393 return
394 wrS c.st fun s => { s with length := l.hold.toUInt32 &&& 0xffff }
395 INITBITS
396 -- while (state->length != 0) { copy = state->length; PULL(); ROOM(); ... }
397 xwhile
398 (do return (← rdS c.st (·.length)) != 0)
399 (do
400 let s ← ldInflateState c.st
401 modify fun l => { l with copy := s.length }
402 PULL c
403 ROOM c
404 let l ← get
405 let mut copy := l.copy
406 if copy > l.have_ then copy := l.have_
407 if copy > l.left then copy := l.left
408 memcpyB l.put l.next copy.toNat
409 let nx ← l.next.add (copy.toNat : Int)
410 let pt ← l.put.add (copy.toNat : Int)
411 set { l with copy := copy, have_ := l.have_ - copy, next := nx, left := l.left - copy, put := pt }
412 wrS c.st fun s => { s with length := s.length - copy })
413 setMode c.st TYPE
414
415/-- `case TYPE:` -/
416def back_TYPE (c : BCtx) : X Unit := do
417 -- if (state->last) { BYTEBITS(); state->mode = DONE; break; }
418 if (← rdS c.st (·.last)) != 0 then
419 BYTEBITS
420 setMode c.st DONE
421 return
422 NEEDBITS c 3
423 let b ← BITS 1
424 wrS c.st fun s => { s with last := u2i b }
425 DROPBITS 1
426 match (← BITS 2) with
427 | 0 => setMode c.st STORED
428 | 1 =>
429 inflate_fixed c.st
430 setMode c.st LEN
431 | 2 => setMode c.st TABLE
432 | _ => badMode c "invalid block type"
433 DROPBITS 2
434
435/-- The `switch (state->mode)` of `inflateBack()`. -/
436def back_dispatch (c : BCtx) : X Unit := do
437 let m ← rdS c.st (·.mode)
438 if m == TYPE then back_TYPE c
439 else if m == STORED then back_STORED c
440 else if m == TABLE then back_TABLE c
441 else if m == LEN then back_LEN c
442 else if m == DONE then
443 -- ret = Z_STREAM_END; goto inf_leave;
444 modify fun l => { l with ret := Z_STREAM_END }
445 throw Ex.leave
446 else if m == BAD then
447 modify fun l => { l with ret := Z_DATA_ERROR }
448 throw Ex.leave
449 else
450 -- default: ret = Z_STREAM_ERROR; goto inf_leave;
451 modify fun l => { l with ret := Z_STREAM_ERROR }
452 throw Ex.leave
453
454/-- `int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)` -/
455def inflateBack (strm : ZStreamPtr) (inCb : InCb) (in_desc : BPtr) (outCb : OutCb) (out_desc : BPtr) : M Int32 := do
456 -- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
457 if strm == none then return Z_STREAM_ERROR
458 let z ← ldZStream strm
459 if z.state == none then return Z_STREAM_ERROR
460 -- state = (struct inflate_state FAR *)strm->state;
461 let st ← castInflateState z.state
462 -- strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0;
463 wrZ strm fun z => { z with msg := .null }
464 wrS st fun s => { s with mode := TYPE, last := 0, whave := 0 }
465 -- next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0;
466 let z ← ldZStream strm
467 let s ← ldInflateState st
468 let next := z.next_in
469 let have_ := if next != .null then z.avail_in else 0
470 -- put = state->window; left = state->wsize;
471 let l0 : IL := { IL.init with next := next, have_ := have_, hold := 0, bits := 0, put := s.window, left := s.wsize }
472 let c : BCtx := { strm, st, inCb, inDesc := in_desc, outCb, outDesc := out_desc }
473 -- for (;;) switch (state->mode) { ... }
474 let (_, l) ← StateT.run (ExceptT.run (xwhile (pure true) (back_dispatch c))) l0
475 -- inf_leave: if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left) && ret == Z_STREAM_END) ret = Z_BUF_ERROR; }
476 let s ← ldInflateState st
477 let mut ret := l.ret
478 if l.left < s.wsize then
479 if (← outCb out_desc s.window (s.wsize - l.left)) != 0 && ret == Z_STREAM_END then ret := Z_BUF_ERROR
480 -- strm->next_in = next; strm->avail_in = have; return ret;
481 wrZ strm fun z => { z with next_in := l.next, avail_in := l.have_ }
482 return ret
483
484/-- `int ZEXPORT inflateBackEnd(z_streamp strm)` -/
485def inflateBackEnd (strm : ZStreamPtr) : M Int32 := do
486 -- if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR;
487 if strm == none then return Z_STREAM_ERROR
488 let z ← ldZStream strm
489 if z.state == none || z.zfree == .null then return Z_STREAM_ERROR
490 -- ZFREE(strm, strm->state); strm->state = Z_NULL;
491 let st ← castInflateState z.state
492 ZFREES strm st
493 wrZ strm fun z => { z with state := none }
494 return Z_OK
495
496end Zlib.Infback