1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
use bufio;
use bytes;
use io;
use memio;
export type idat_reader = struct {
vtable: io::stream,
src: *reader,
};
// Returns a new IDAT reader, which reads consecutive IDAT chunks from a
// [[reader]] and outputs their raw (compressed) contents as a continuous data
// stream. Instead of reading from this directly, users are advised to construct
// a [[decoder]] with [[newdecoder]], and use that to read the uncompressed
// pixel data.
//
// This stream does not need to be closed.
export fn new_idat_reader(src: *reader) idat_reader = {
assert(chunk_type(src) == IDAT,
"Attempted to create IDAT reader for non-IDAT chunk");
return idat_reader {
vtable = &idat_reader_vtable,
src = src,
};
};
const idat_reader_vtable: io::vtable = io::vtable {
reader = &idat_read,
...
};
fn idat_read(
st: *io::stream,
buf: []u8,
) (size | io::EOF | io::error) = {
let st = st: *idat_reader;
assert(st.vtable == &idat_reader_vtable);
for (true) match (io::read(st.src, buf)?) {
case io::EOF =>
match (nextchunk(st.src)) {
case let err: (invalid | unsupported) =>
return wraperror(err);
case let err: io::error =>
return err;
case io::EOF =>
return io::EOF;
case let ctype: u32 =>
if (ctype != IDAT) {
return io::EOF;
};
};
case let z: size =>
return z;
};
};
@test fn idat_reader() void = {
const src = memio::fixed(no_filtering);
const read = newreader(&src) as reader;
assert(nextchunk(&read) as u32 == IHDR);
const ihdr = ihdr_read(&read)!;
let pixbuf: []u8 = alloc([0...], decoder_bufsiz(&ihdr));
defer free(pixbuf);
for (true) {
const ctype = nextchunk(&read) as u32;
if (ctype == IDAT) {
break;
};
io::copy(io::empty, &read)!;
};
let idat = new_idat_reader(&read);
let dec = newdecoder(&idat, &ihdr, pixbuf)!;
defer io::close(&dec)!;
const pixels = io::drain(&dec)!;
defer free(pixels);
assert(bytes::equal(pixels, no_filtering_data));
};
|