Skip to content
REFERENCE / ZLIB × LEAN

compress.c.lean

Source snapshot · e204579742a32ca8 · 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.«deflate.c»
2
3/-!
4# compress.c — faithful translation
5
6Source: `compress.c` of the verified source. `z_size_t *destLen` and `uLongf *destLen` are modelled as an input
7value (`none` is a NULL pointer) and a result (the value stored through the pointer); the runtime has no pointer to a
8scalar cell. `compress2` reads `*destLen` before any NULL test (R-2 of the notes), so a NULL `destLen` there is
9`Fault.ub`. `deflateInit(&stream, level)` is `deflateInit_(&stream, level, ZLIB_VERSION, (int)sizeof(z_stream))`.
10`z_stream stream` is an automatic record in the `streams` table. Creating it cannot fail or
11consume a default-allocator call; it is freed before the returns.
12-/
13
14namespace Zlib.Compress
15open C Zlib.Deflate
16
17/-- Pointer difference `p - q` with the model's allowance for `NULL - NULL` (D-4). -/
18def ptrDiff (p q : BPtr) : M Int64 :=
19  if p == .null && q == .null then pure 0 else Ptr.diff p q
20
21/-- Automatic storage for the local `z_stream`. As in `uncompr.c`, the runtime creates a fresh
22record without consulting or advancing the allocation-failure oracle. Only the subsequent
23`deflateInit` allocations are default-allocator calls in the C. -/
24def allocLocalZ : M ZStreamPtr := fun h =>
25  match allocZStream { h with allocOk := fun _ => true } with
26  | .ok (p, h') => .ok (p, { h' with allocOk := h.allocOk, nalloc := h.nalloc })
27  | .error e => .error e
28
29/-- `int ZEXPORT compress2_z(Bytef *dest, z_size_t *destLen, const Bytef *source, z_size_t sourceLen, int level)`;
30the result is the return value and the value stored in `*destLen` (unchanged `none` when NULL). -/
31def compress2_z (dest : BPtr) (destLen : Option UInt64) (source : BPtr) (sourceLen : UInt64) (level : Int32) :
32    M (Int32 × Option UInt64) := do
33  let max : UInt32 := 0xffffffff                       -- const uInt max = (uInt)-1;
34  -- if ((sourceLen > 0 && source == Z_NULL) || destLen == Z_NULL || (*destLen > 0 && dest == Z_NULL)) return Z_STREAM_ERROR;
35  let some dl := destLen | return (Z_STREAM_ERROR, none)
36  if (sourceLen > 0 && source == .null) || (dl > 0 && dest == .null) then return (Z_STREAM_ERROR, destLen)
37  -- left = *destLen; *destLen = 0;
38  let mut left : UInt64 := dl
39  -- z_stream stream;  stream.zalloc = 0; stream.zfree = 0; stream.opaque = 0;
40  let strm ← allocLocalZ
41  zwr strm (fun z => { z with zalloc := FnPtr.null, zfree := FnPtr.null, «opaque» := .null })
42  -- err = deflateInit(&stream, level); if (err != Z_OK) return err;
43  let ver ← Zlib.Zutil.zlibVersion
44  let mut err ← deflateInit_ strm level ver sizeof_z_stream
45  if err != Z_OK then
46    freeZStream strm
47    return (err, some 0)
48  -- stream.next_out = dest; stream.avail_out = 0; stream.next_in = source; stream.avail_in = 0;
49  zwr strm (fun z => { z with next_out := dest, avail_out := 0, next_in := source, avail_in := 0 })
50  let mut sourceLen := sourceLen
51  -- do { ... } while (err == Z_OK);
52  let (e, l, sl) ← cdoWhile
53    (fun ((_, left, sourceLen) : Int32 × UInt64 × UInt64) => do
54      let mut left := left
55      let mut sourceLen := sourceLen
56      -- if (stream.avail_out == 0) { stream.avail_out = left > (z_size_t)max ? max : (uInt)left; left -= stream.avail_out; }
57      if (← zrd strm (·.avail_out)) == 0 then
58        let ao : UInt32 := if left > max.toUInt64 then max else left.toUInt32
59        zwr strm (fun z => { z with avail_out := ao })
60        left := left - ao.toUInt64
61      -- if (stream.avail_in == 0) { stream.avail_in = sourceLen > (z_size_t)max ? max : (uInt)sourceLen; sourceLen -= stream.avail_in; }
62      if (← zrd strm (·.avail_in)) == 0 then
63        let ai : UInt32 := if sourceLen > max.toUInt64 then max else sourceLen.toUInt32
64        zwr strm (fun z => { z with avail_in := ai })
65        sourceLen := sourceLen - ai.toUInt64
66      -- err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
67      let err ← deflate strm (if sourceLen != 0 then Z_NO_FLUSH else Z_FINISH)
68      pure (err, left, sourceLen))
69    (fun (st : Int32 × UInt64 × UInt64) => pure (st.1 == Z_OK, st))
70    (err, left, sourceLen)
71  err := e
72  left := l
73  sourceLen := sl
74  -- *destLen = (z_size_t)(stream.next_out - dest);
75  let no ← zrd strm (·.next_out)
76  let n ← ptrDiff no dest
77  -- deflateEnd(&stream);
78  let _ ← deflateEnd strm
79  freeZStream strm
80  -- return err == Z_STREAM_END ? Z_OK : err;
81  return (if err == Z_STREAM_END then Z_OK else err, some n.toUInt64)
82
83/-- `int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)`;
84`destLen` is the value of `*destLen`, `none` for NULL (undefined: `*destLen` is read first). -/
85def compress2 (dest : BPtr) (destLen : Option UInt64) (source : BPtr) (sourceLen : UInt64) (level : Int32) :
86    M (Int32 × UInt64) := do
87  -- z_size_t got = *destLen;
88  let some got := destLen | ub "null dereference of destLen"
89  -- ret = compress2_z(dest, &got, source, sourceLen, level);
90  let (ret, g) ← compress2_z dest (some got) source sourceLen level
91  -- *destLen = (uLong)got;
92  return (ret, g.getD got)
93
94/-- `int ZEXPORT compress_z(Bytef *dest, z_size_t *destLen, const Bytef *source, z_size_t sourceLen)` -/
95def compress_z (dest : BPtr) (destLen : Option UInt64) (source : BPtr) (sourceLen : UInt64) :
96    M (Int32 × Option UInt64) :=
97  compress2_z dest destLen source sourceLen Z_DEFAULT_COMPRESSION
98
99/-- `int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)` -/
100def compress (dest : BPtr) (destLen : Option UInt64) (source : BPtr) (sourceLen : UInt64) :
101    M (Int32 × UInt64) :=
102  compress2 dest destLen source sourceLen Z_DEFAULT_COMPRESSION
103
104/-- `z_size_t ZEXPORT compressBound_z(z_size_t sourceLen)` -/
105def compressBound_z (sourceLen : UInt64) : UInt64 :=
106  let bound := sourceLen + (sourceLen >>> 12) + (sourceLen >>> 14) + (sourceLen >>> 25) + 13
107  if bound < sourceLen then 0xffffffffffffffff else bound
108
109/-- `uLong ZEXPORT compressBound(uLong sourceLen)` -/
110def compressBound (sourceLen : UInt64) : UInt64 :=
111  -- (uLong)bound != bound is always false: both are 64 bits
112  compressBound_z sourceLen
113
114end Zlib.Compress
ZLIB × LEAN

Global contents

READING NOWcompress.c.lean