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

Header.lean

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

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

1import ZlibF.Spec.Api.Basic
2
3/-!
4# API model: the gzip header record (`gz_header`)
5
6The part of `gz_header` that `deflateSetHeader` writes and `inflateGetHeader` reads
7(`zlib.h`), as plain data. Pointers become `Option (List UInt8)` (`none` is `Z_NULL`).
8-/
9
10namespace ZlibF.Spec.Api
11
12open ZlibF.Spec
13
14/-- `gz_header` as `deflateSetHeader` sees it: `extra`, `name`, `comment` are `none` for a null
15pointer. `name` and `comment` hold no zero byte (they are zero-terminated strings) and `extra`
16has fewer than `2^16` bytes. `xflags` is not used when writing. -/
17structure GzHead where
18  text : Bool
19  time : Nat
20  os : Nat
21  extra : Option (List UInt8)
22  name : Option (List UInt8)
23  comment : Option (List UInt8)
24  hcrc : Bool
25  deriving DecidableEq, Repr
26
27/-- The header record can be written (`deflateSetHeader` precondition of `zlib.h`). -/
28def GzHead.Valid (h : GzHead) : Prop :=
29  (∀ e, h.extra = some e → e.length < 2 ^ 16) ∧ (∀ s, h.name = some s → 0 ∉ s) ∧
30    (∀ s, h.comment = some s → 0 ∉ s)
31
32/-- The `OS_CODE` of the default x86_64 Linux build. -/
33def osCode : Nat := 3
34
35/-- The default header that `deflate` writes without `deflateSetHeader` (`deflate.c`): no flags,
36`MTIME = 0`, `OS = OS_CODE`. -/
37def GzHead.default : GzHead := ⟨false, 0, osCode, none, none, none, false⟩
38
39/-- `XFL` written by `deflate` (`deflate.c`): 2 for level 9, 4 for the fastest algorithms
40(level below 2, or Huffman only or run-length strategy), else 0. -/
41def xflOf (p : DeflParams) : Nat :=
42  if p.level = 9 then 2 else if p.strategy ≥ 2 ∨ p.level < 2 then 4 else 0
43
44/-- The flag byte `FLG` of a header record. -/
45def GzHead.flg (h : GzHead) : Nat :=
46  (if h.text then 1 else 0) + (if h.hcrc then 2 else 0) + (if h.extra.isSome then 4 else 0) +
47    (if h.name.isSome then 8 else 0) + (if h.comment.isSome then 16 else 0)
48
49/-- The header without the optional header CRC, as `Gzip.header` of the format specification. -/
50def GzHead.core (p : DeflParams) (h : GzHead) : List UInt8 :=
51  Gzip.header h.flg.toUInt8 (le32 h.time) (xflOf p).toUInt8 h.os.toUInt8
52    (h.extra.getD []) (h.name.getD []) (h.comment.getD [])
53
54/-- The bytes that `deflate` writes before the deflate data: the header and, if `hcrc`, the low
5516 bits of the CRC-32 of the header (RFC 1952). -/
56def GzHead.bytes (p : DeflParams) (h : GzHead) : List UInt8 :=
57  h.core p ++ (if h.hcrc then le16 ((crc32 (h.core p)).toNat % 2 ^ 16) else [])
58
59/-- A gzip member with the given header bytes, that decodes to `out`: the header bytes, deflate
60data, the little-endian CRC-32 and length of `out` (`Gzip.Decodes` with the header fixed). -/
61def Gzip.DecodesWith (hdr stream out : List UInt8) : Prop :=
62  ∃ s, stream = hdr ++ s ∧ Deflate.Prefix [] s (le32 (crc32 out).toNat ++ le32 (out.length % 2 ^ 32)) out
63
64/-- What `inflateGetHeader` was given: whether `extra`, `name`, `comment` have a buffer and its
65size (`extra_max`, `name_max`, `comm_max`). -/
66structure HdrReq where
67  extraMax : Option Nat
68  nameMax : Option Nat
69  commMax : Option Nat
70  deriving DecidableEq, Repr
71
72/-- The record after `inflate` has read the header (`done = 1`), or `done = -1` for a zlib
73stream. `extraLen` is `extra_len`. -/
74structure GzHdrOut where
75  text : Bool
76  time : Nat
77  xflags : Nat
78  os : Nat
79  extra : Option (List UInt8)
80  extraLen : Nat
81  name : Option (List UInt8)
82  comment : Option (List UInt8)
83  hcrc : Bool
84  done : Int
85  deriving DecidableEq, Repr
86
87/-- What `inflate` stores for a gzip header with the given fields (`A-header-fill`, `inflate.c`
88cases `HEAD` to `HCRC`): `text`, `time`, `xflags`, `os`; `extra` truncated to `extra_max` and
89`extra_len` the full length; the name and the comment including their zero terminator,
90truncated to `name_max` and `comm_max`; a field that is absent in the stream, or that has no
91buffer, is stored as `Z_NULL`; `hcrc` from the flag; `done = 1`. -/
92def fillHeader (req : HdrReq) (flg : Nat) (mtime : Nat) (xfl os : Nat)
93    (extra name comment : List UInt8) : GzHdrOut where
94  text := flg % 2 = 1
95  time := mtime
96  xflags := xfl
97  os := os
98  extra := if flg / 4 % 2 = 1 then req.extraMax.map (fun m => extra.take m) else none
99  extraLen := if flg / 4 % 2 = 1 then extra.length else 0
100  name := if flg / 8 % 2 = 1 then req.nameMax.map (fun m => (name ++ [0]).take m) else none
101  comment := if flg / 16 % 2 = 1 then req.commMax.map (fun m => (comment ++ [0]).take m) else none
102  hcrc := flg / 2 % 2 = 1
103  done := 1
104
105/-- The header record is complete in the bytes `seen`: a valid gzip header (as written by
106`Gzip.header`, with its header CRC if `FHCRC`) starts `seen`, and the record is `fillHeader` of its
107fields. Used by the inflate model; for a zlib stream `done = -1`. -/
108def HeaderRead (req : HdrReq) (seen : List UInt8) (h : GzHdrOut) : Prop :=
109  (∃ (flg : UInt8) (mtime : List UInt8) (xfl os : UInt8) (extra name comment r : List UInt8),
110    flg.toNat < 32 ∧ mtime.length = 4 ∧ extra.length < 2 ^ 16 ∧ 0 ∉ name ∧ 0 ∉ comment ∧
111    seen = Gzip.header flg mtime xfl os extra name comment ++
112        (if flg.toNat / 2 % 2 = 1 then
113          le16 ((crc32 (Gzip.header flg mtime xfl os extra name comment)).toNat % 2 ^ 16) else []) ++ r ∧
114    h = fillHeader req flg.toNat (mtime.foldr (fun b a => a * 256 + b.toNat) 0) xfl.toNat os.toNat
115          extra name comment) ∨
116  (∃ cmf flg r, seen = cmf :: flg :: r ∧ Zlib.HeaderOK cmf flg ∧ h.done = -1)
117
118end ZlibF.Spec.Api
ZLIB × LEAN

全局目录

当前位置Header.lean