Skip to content
REFERENCE / ZLIB × LEAN

uncompr.c.lean

Source snapshot · 28e4f7e472483478 · 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.«gzguts.h»
2import ZlibF.Zlib.«inflate.c»
3
4/-!
5# uncompr.c — faithful translation
6
7Source: `uncompr.c` of the verified source, default x86_64 Linux build.
8
9Decisions (see `docs/design/external-io.md`):
10* `z_stream stream;` is a local record made by `allocLocalZ` (no allocation oracle: automatic storage cannot fail),
11  with arbitrary content, and freed before every return.
12* `(Bytef *)&stream.reserved` (D-5) is a local 8-byte block, freed before every return. It is only ever passed as
13  `next_out` with `avail_out == 0`.
14* A pointer to a scalar (`z_size_t *destLen`, `uLong *sourceLen`) is a pointer to an 8-byte block holding the
15  value in little-endian order (`load64`/`store64` of `gzguts.h.lean`).
16* `inflateInit(&stream)` is `inflateInit_(&stream, ZLIB_VERSION, (int)sizeof(z_stream))`, `sizeof(z_stream) == 112`.
17-/
18
19namespace Zlib.Uncompr
20open C Zlib.GzFs Zlib.Gzguts
21open Zlib.Inflate (inflateInit_ inflate inflateEnd)
22
23/-- A local `z_stream`: a fresh record with arbitrary integers and null pointers, outside the allocation oracle
24(automatic storage cannot fail). Made by the runtime allocator `allocZStream` with the oracle set to succeed. -/
25def allocLocalZ : M ZStreamPtr := fun h =>
26  match allocZStream { h with allocOk := fun _ => true } with
27  | .ok (p, h') => .ok (p, { h' with allocOk := h.allocOk, nalloc := h.nalloc })
28  | .error e => .error e
29
30structure UncLoop where
31  err : Int32
32  len : UInt64
33  left : UInt64
34
35/-- `int ZEXPORT uncompress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source, z_size_t *sourceLen)` -/
36def uncompress2_z (dest : BPtr) (destLen : BPtr) (source : BPtr) (sourceLen : BPtr) : M Int32 := do
37  -- z_stream stream; int err; const uInt max = (uInt)-1; z_size_t len, left;
38  let stream ← allocLocalZ
39  let reserved ← allocLocal 8
40  let max : UInt32 := 0xFFFFFFFF
41  let free : M Unit := do
42    freeB reserved
43    freeZStream stream
44  -- if (sourceLen == Z_NULL || (*sourceLen > 0 && source == Z_NULL) || destLen == Z_NULL || (*destLen > 0 && dest == Z_NULL))
45  --   return Z_STREAM_ERROR;
46  let mut bad := false
47  if sourceLen == .null then bad := true
48  else if (← load64 sourceLen) > 0 && source == .null then bad := true
49  else if destLen == .null then bad := true
50  else if (← load64 destLen) > 0 && dest == .null then bad := true
51  if bad then
52    free
53    return Z_STREAM_ERROR
54  -- len = *sourceLen; left = *destLen;
55  let len ← load64 sourceLen
56  let left ← load64 destLen
57  -- if (left == 0 && dest == Z_NULL) dest = (Bytef *)&stream.reserved;
58  let dest := if left == 0 && dest == .null then reserved else dest
59  -- stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; zalloc, zfree, opaque = 0;
60  updZ stream fun z => { z with next_in := source, avail_in := 0, zalloc := .null, zfree := .null, «opaque» := .null }
61  -- err = inflateInit(&stream); if (err != Z_OK) return err;
62  let ver ← Zlib.GzFs.strLit ZLIB_VERSION
63  let err ← inflateInit_ stream ver 112
64  if err != Z_OK then
65    free
66    return err
67  -- stream.next_out = dest; stream.avail_out = 0;
68  updZ stream fun z => { z with next_out := dest, avail_out := 0 }
69  -- do { ... } while (err == Z_OK);
70  let l ← cdoWhile
71    (fun (l : UncLoop) => do
72      let mut l := l
73      -- if (stream.avail_out == 0) { stream.avail_out = left > (z_size_t)max ? max : (uInt)left; left -= stream.avail_out; }
74      if (← ldZ stream).avail_out == 0 then
75        let a : UInt32 := if l.left > max.toUInt64 then max else l.left.toUInt32
76        updZ stream fun z => { z with avail_out := a }
77        l := { l with left := l.left - a.toUInt64 }
78      -- if (stream.avail_in == 0) { stream.avail_in = len > (z_size_t)max ? max : (uInt)len; len -= stream.avail_in; }
79      if (← ldZ stream).avail_in == 0 then
80        let a : UInt32 := if l.len > max.toUInt64 then max else l.len.toUInt32
81        updZ stream fun z => { z with avail_in := a }
82        l := { l with len := l.len - a.toUInt64 }
83      -- err = inflate(&stream, Z_NO_FLUSH);
84      let err ← inflate stream Z_NO_FLUSH
85      return { l with err })
86    (fun l => pure (l.err == Z_OK, l))
87    { err, len, left }
88  -- len += stream.avail_in; left += stream.avail_out; *sourceLen -= len; *destLen -= left;
89  let z ← ldZ stream
90  let len := l.len + z.avail_in.toUInt64
91  let left := l.left + z.avail_out.toUInt64
92  store64 sourceLen ((← load64 sourceLen) - len)
93  store64 destLen ((← load64 destLen) - left)
94  -- inflateEnd(&stream);
95  let _ ← inflateEnd stream
96  -- return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && len == 0 ? Z_DATA_ERROR : err;
97  let err := l.err
98  let r : Int32 :=
99    if err == Z_STREAM_END then Z_OK
100    else if err == Z_NEED_DICT then Z_DATA_ERROR
101    else if err == Z_BUF_ERROR && len == 0 then Z_DATA_ERROR
102    else err
103  free
104  return r
105
106/-- `int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen)` -/
107def uncompress2 (dest : BPtr) (destLen : BPtr) (source : BPtr) (sourceLen : BPtr) : M Int32 := do
108  -- int ret; z_size_t got = *destLen, used = *sourceLen;
109  let got ← allocLocal 8
110  let used ← allocLocal 8
111  store64 got (← load64 destLen)
112  store64 used (← load64 sourceLen)
113  -- ret = uncompress2_z(dest, &got, source, &used);
114  let ret ← uncompress2_z dest got source used
115  -- *sourceLen = (uLong)used; *destLen = (uLong)got;
116  store64 sourceLen (← load64 used)
117  store64 destLen (← load64 got)
118  freeB got
119  freeB used
120  return ret
121
122/-- `int ZEXPORT uncompress_z(Bytef *dest, z_size_t *destLen, const Bytef *source, z_size_t sourceLen)` -/
123def uncompress_z (dest : BPtr) (destLen : BPtr) (source : BPtr) (sourceLen : UInt64) : M Int32 := do
124  -- z_size_t used = sourceLen;
125  let used ← allocLocal 8
126  store64 used sourceLen
127  let r ← uncompress2_z dest destLen source used
128  freeB used
129  return r
130
131/-- `int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)` -/
132def uncompress (dest : BPtr) (destLen : BPtr) (source : BPtr) (sourceLen : UInt64) : M Int32 := do
133  -- uLong used = sourceLen;
134  let used ← allocLocal 8
135  store64 used sourceLen
136  let r ← uncompress2 dest destLen source used
137  freeB used
138  return r
139
140end Zlib.Uncompr
ZLIB × LEAN

Global contents

READING NOWuncompr.c.lean