# baked_stream.ludic - a large bake read a piece at a time (placements by chunk, terrain by tile): the # header checked once, the file kept open, and each read into the caller's own buffer at a payload # offset, so a ring streaming chunks in makes nothing per chunk. Pack-aware (file_open) export property BakedFile { f: pointer = null off: int = 0 # where the payload starts in the file n: long = 0 # the payload's length } # this bake's file kept open for reading, or null (missing, or another format, key or version) @alloc_ok("once per baked file opened: its header and record") export function baked_open_range(path: string, key: string, version: int) -> BakedFile { let f = file_open(path, "rb") if f == null { return null } let want = 32 + len(key) + 1 let h = buffer(want) if file_read(f, h, want) != want or bk_head_ok(h, want, key, version) < 0 { file_close(f) return null } let bf = new BakedFile bf.f = f bf.off = bk_u32(h, 12) bf.n = bk_u64(h, 24) return bf } # `n` bytes from payload offset `at` into `into` (from its start): the count read, 0 on a failure; # held to the buffer and to the payload export function baked_read(bf: BakedFile, at: int, n: int, into: []byte) -> int { if bf == null or bf.f == null or at < 0 or n <= 0 { return 0 } var k = n if k > len(into) { k = len(into) } if long(at) + long(k) > bf.n { k = int(bf.n - long(at)) } if k <= 0 { return 0 } if file_seek(bf.f, bf.off + at, 0) != 0 { return 0 } return file_read(bf.f, into, k) } export function baked_len(bf: BakedFile) -> long { if bf == null { return 0 } return bf.n } export function baked_close(bf: BakedFile) -> void { if bf == null or bf.f == null { return } file_close(bf.f) bf.f = null }