~/bend-docscommunity

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.

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.