archive/archive.bend relies on unsafe/foreign
raw source on the hub · import 0x9abf4483e85cdd9418700acfbda3e5a0/archive/archive.bend as Archive
ZIP archives read over Bytes: stored and DEFLATE entries, checked against their CRC-32 and sizes. Source: https://github.com/paymog/bend-kit/tree/main/archive
5 imports
import Base import ../bytes/bytes.bend as Bytes import 0x49814d83de8f70993a43e1002be29ecd/bytes.bend as HubBytes import bend-kit-zlib@0.1.6.0/zlib.bend as Zlib import bend-kit-hash@0.1.0.0/hash.bend as Hash
Types
type Entry source · line 9 · raw
Type
One member: its name and contents as raw bytes, its method (0 stored, 8 DEFLATE), and its CRC-32.
Entry@name:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @data:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @method:U32 -> @crc:U32 -> Entry
type Header source · line 14 · raw
Data
A checked central directory entry. name and data are byte offsets into the input; packed is the stored or compressed length, size the length after decoding.
Header@name:U32 -> @name_len:U32 -> @method:U32 -> @crc:U32 -> @packed:U32 -> @size:U32 -> @data:U32 -> Header
Definitions
def supported source · line 18 · raw
@+method:U32 -> Bool
The methods read: 0 (stored) and 8 (DEFLATE).
def crc.local source · line 22 · raw
@r:Pair(0x49814d83de8f70993a43e1002be29ecd/bytes.Bytes, U32) -> Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, U32)
Hash uses the published Bytes type; transfer the array without copying.
def crc.bytes source · line 26 · raw
@b:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, U32)
def crc.value source · line 30 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, U32) -> U32
def crc32 source · line 34 · raw
@b:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> U32
def grab.go source · line 38 · raw
@k:Nat -> @r:Pair(Array<U32>, U32) -> @+j:U32 -> @acc:List<&2, U32> -> Pair(Array<U32>, List<&2, U32>)
n bytes from i as a list. Callers keep i + n within the buffer.
def grab source · line 47 · raw
@a:Array<U32> -> @+i:U32 -> @+n:U32 -> Pair(Array<U32>, List<&2, U32>)
def at source · line 51 · raw
@xs:List<&2, U32> -> @+i:U32 -> U32
def u16 source · line 59 · raw
@+xs:List<&2, U32> -> @+o:U32 -> U32
Little-endian fields of a grabbed record.
def u32 source · line 62 · raw
@+xs:List<&2, U32> -> @+o:U32 -> U32
def why source · line 66 · raw
@+ok:Bool -> @+msg:String -> @+rest:Maybe<&2, String> -> Maybe<&2, String>
The first failed check's message, outermost first.
def encrypted source · line 70 · raw
@+flags:U32 -> Bool
General purpose flags: encrypted (bit 0), strong encryption (bit 6), masked headers (bit 13).
def same.at3 source · line 74 · raw
@r:Pair(Array<U32>, U32) -> @+u:U32 -> Pair(Array<U32>, Bool)
Do n bytes at x and at y match? r holds the previous byte's answer.
def same.at2 source · line 78 · raw
@r:Pair(Array<U32>, U32) -> @+y:U32 -> Pair(Array<U32>, Bool)
def same.go source · line 82 · raw
@n:Nat -> @r:Pair(Array<U32>, Bool) -> @+x:U32 -> @+y:U32 -> Pair(Array<U32>, Bool)
def eocd.of source · line 95 · raw
@r:Pair(Array<U32>, List<&2, U32>) -> @+len:U32 -> @+p:U32 -> Pair(Array<U32>, Bool)
End of central directory (APPNOTE 4.3.16): the last signature whose comment length reaches the end exactly.
def eocd.win source · line 99 · raw
@a:Array<U32> -> @+len:U32 -> @+p:U32 -> Pair(Array<U32>, Bool)
def eocd.go source · line 103 · raw
@f:Nat -> @r:Pair(Array<U32>, Bool) -> @+len:U32 -> @+p:U32 -> Pair(Array<U32>, Maybe<&2, U32>)
f counts the positions left below p; a comment is at most 65535 bytes.
def cd.fin.end source · line 116 · raw
@ok:Bool -> @acc:List<&2, Header> -> Result<&1, &1, Pair(U32, String), List<&2, Header>>
def cd.fin source · line 123 · raw
@res:Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)> -> @+end:U32 -> Result<&1, &1, Pair(U32, String), List<&2, Header>>
def lh.push source · line 130 · raw
@ok:Bool -> @a:Array<U32> -> @+hd:Header -> @+next:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def lh.same source · line 137 · raw
@r:Pair(Array<U32>, Bool) -> @+hd:Header -> @+next:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def lh.name source · line 141 · raw
@err:Maybe<&2, String> -> @a:Array<U32> -> @+lname:U32 -> @+hd:Header -> @+next:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def lh.err source · line 150 · raw
@+l:List<&2, U32> -> @+method:U32 -> @+nlen:U32 -> @+packed:U32 -> @+cdoff:U32 -> @+lname:U32 -> @+extra:U32 -> Maybe<&2, String>
Local file header (APPNOTE 4.3.7): it must agree with the central directory, and its data must end before the directory.
def lh.head source · line 159 · raw
@r:Pair(Array<U32>, List<&2, U32>) -> @+h:List<&2, U32> -> @+p:U32 -> @+next:U32 -> @+cdoff:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def lh.at source · line 168 · raw
@ok:Bool -> @a:Array<U32> -> @+h:List<&2, U32> -> @+p:U32 -> @+next:U32 -> @+cdoff:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def cd.err source · line 176 · raw
@+h:List<&2, U32> -> @+p:U32 -> @+end:U32 -> Maybe<&2, String>
Central directory file header (APPNOTE 4.3.12) at p, with the directory ending at end.
def cd.head.of source · line 190 · raw
@err:Maybe<&2, String> -> @a:Array<U32> -> @+h:List<&2, U32> -> @+p:U32 -> @+cdoff:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def cd.head source · line 198 · raw
@r:Pair(Array<U32>, List<&2, U32>) -> @+p:U32 -> @+end:U32 -> @+cdoff:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def cd.entry source · line 202 · raw
@ok:Bool -> @a:Array<U32> -> @+p:U32 -> @+end:U32 -> @+cdoff:U32 -> @acc:List<&2, Header> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>)
def cd.go source · line 210 · raw
@k:Nat -> @r:Pair(Array<U32>, Result<&1, &1, Pair(U32, String), Pair(U32, List<&2, Header>)>) -> @+end:U32 -> @+cdoff:U32 -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
k entries left; r holds the next header's offset and the headers so far, reversed.
def eocd.err source · line 223 · raw
@+x:List<&2, U32> -> @+e:U32 -> Maybe<&2, String>
def eocd.checked source · line 229 · raw
@err:Maybe<&2, String> -> @a:Array<U32> -> @+x:List<&2, U32> -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
def eocd.parse source · line 237 · raw
@r:Pair(Array<U32>, List<&2, U32>) -> @+e:U32 -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
def eocd.found source · line 241 · raw
@r:Pair(Array<U32>, Maybe<&2, U32>) -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
def headers.at source · line 249 · raw
@short:Bool -> @a:Array<U32> -> @+len:U32 -> Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
def headers.fin source · line 257 · raw
@+len:U32 -> @r:Pair(Array<U32>, Result<&1, &1, Pair(U32, String), List<&2, Header>>) -> Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
def headers source · line 262 · raw
@input:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), List<&2, Header>>)
The input back, and its central directory with every bound, local header, and method checked. Pure: no data is decoded.
def inflated source · line 266 · raw
@r:Result<&1, &1, Pair(U32, String), Pair(U32, Array<U32>)> -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def inflate.of source · line 275 · raw
@+size:U32 -> @b:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> IO(Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>)
Output past size is refused inside libz, so a bomb never grows beyond its declared size.
def decode source · line 281 · raw
@stored:Bool -> @+size:U32 -> @raw:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> IO(Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>)
def check.crc.of source · line 288 · raw
@ok:Bool -> @b:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def check.crc source · line 295 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, U32) -> @+crc:U32 -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def check.len.of source · line 299 · raw
@ok:Bool -> @b:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @+crc:U32 -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def check.len source · line 306 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, U32) -> @+size:U32 -> @+crc:U32 -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def check source · line 310 · raw
@+size:U32 -> @+crc:U32 -> @r:Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes> -> Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes>
def one.put source · line 317 · raw
@r:Result<&1, &1, Pair(U32, String), 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes> -> @nm:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @+method:U32 -> @+crc:U32 -> @+left:U32 -> @+size:U32 -> @acc:List<&1, Entry> -> Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>
def one.data source · line 324 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes) -> @nm:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @+method:U32 -> @+crc:U32 -> @+size:U32 -> @+left:U32 -> @acc:List<&1, Entry> -> IO(Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>))
def one.name source · line 330 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, 0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes) -> @+method:U32 -> @+crc:U32 -> @+packed:U32 -> @+size:U32 -> @+data:U32 -> @+left:U32 -> @acc:List<&1, Entry> -> IO(Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>))
def one.cap source · line 335 · raw
@over:Bool -> @input:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @+hd:Header -> @+left:U32 -> @acc:List<&1, Entry> -> IO(Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>))
left: the output still allowed under the caller's max.
def one source · line 343 · raw
@+hd:Header -> @input:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> @+left:U32 -> @acc:List<&1, Entry> -> IO(Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>))
def run.fin source · line 347 · raw
@res:Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)> -> Result<&1, &1, Pair(U32, String), List<&1, Entry>>
def run source · line 354 · raw
@xs:List<&2, Header> -> @st:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), Pair(U32, List<&1, Entry>)>) -> IO(Result<&1, &1, Pair(U32, String), List<&1, Entry>>)
def read.of source · line 369 · raw
@r:Pair(0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes, Result<&1, &1, Pair(U32, String), List<&2, Header>>) -> @+max:U32 -> IO(Result<&1, &1, Pair(U32, String), List<&1, Entry>>)
def read source · line 380 · raw
@max:U32 -> @input:0x9abf4483e85cdd9418700acfbda3e5a0/bytes/bytes.Bytes -> IO(Result<&1, &1, Pair(U32, String), List<&1, Entry>>)
Every entry of a ZIP archive, in central directory order, or the first problem found. Stored (0) and DEFLATE (8) entries only; no ZIP64, encryption, or multi-disk archives. Output past max bytes in total fails with 27 (EFBIG). Malformed ZIP fails with 22 (EINVAL); libz load and allocation errors keep their host codes.