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)); };