| // Copyright 2017 The Wuffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| use "std/adler32" |
| use "std/deflate" |
| |
| pub status "#bad checksum" |
| pub status "#bad compression method" |
| pub status "#bad compression window size" |
| pub status "#bad parity check" |
| |
| pri status "#TODO: unsupported preset dictionary" |
| |
| // TODO: reference deflate.decoder_workbuf_len_max_incl_worst_case. |
| pub const decoder_workbuf_len_max_incl_worst_case base.u64 = 1 |
| |
| pub struct decoder?( |
| ignore_checksum base.bool, |
| checksum adler32.hasher, |
| |
| flate deflate.decoder, |
| |
| util base.utility, |
| ) |
| |
| pub func decoder.set_ignore_checksum!(ic base.bool) { |
| this.ignore_checksum = args.ic |
| } |
| |
| pub func decoder.workbuf_len() base.range_ii_u64 { |
| return this.util.make_range_ii_u64( |
| min_incl:decoder_workbuf_len_max_incl_worst_case, |
| max_incl:decoder_workbuf_len_max_incl_worst_case) |
| } |
| |
| pub func decoder.decode_io_writer?(dst base.io_writer, src base.io_reader, workbuf slice base.u8) { |
| var x base.u16 |
| var checksum_got base.u32 |
| var status base.status |
| var checksum_want base.u32 |
| var mark base.u64 |
| |
| x = args.src.read_u16be?() |
| if ((x >> 8) & 0x0F) <> 0x08 { |
| return "#bad compression method" |
| } |
| if (x >> 12) > 0x07 { |
| return "#bad compression window size" |
| } |
| if (x & 0x20) <> 0 { |
| return "#TODO: unsupported preset dictionary" |
| } |
| if (x % 31) <> 0 { |
| return "#bad parity check" |
| } |
| |
| // Decode and checksum the DEFLATE-encoded payload. |
| while true { |
| mark = args.dst.mark() |
| status =? this.flate.decode_io_writer?(dst:args.dst, src:args.src, workbuf:args.workbuf) |
| if not this.ignore_checksum { |
| checksum_got = this.checksum.update!(x:args.dst.since(mark:mark)) |
| } |
| if status.is_ok() { |
| break |
| } |
| yield? status |
| } |
| checksum_want = args.src.read_u32be?() |
| if (not this.ignore_checksum) and (checksum_got <> checksum_want) { |
| return "#bad checksum" |
| } |
| } |