| // Copyright 2017 The Puffs 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. |
| |
| pub error "invalid zlib compression method" |
| pub error "invalid zlib compression window size" |
| pub error "invalid zlib parity check" |
| |
| pub error "TODO: unsupported zlib preset dictionary" |
| |
| pub struct zlib_decoder?( |
| dec decoder, |
| adler adler32, |
| ) |
| |
| pub func zlib_decoder.decode?(dst writer1, src reader1)() { |
| var x u16 = in.src.read_u16be?() |
| if ((x >> 8) & 0x0F) != 0x08 { |
| return error "invalid zlib compression method" |
| } |
| if (x >> 12) > 0x07 { |
| return error "invalid zlib compression window size" |
| } |
| if (x & 0x20) != 0 { |
| return error "TODO: unsupported zlib preset dictionary" |
| } |
| if (x % 31) != 0 { |
| return error "invalid zlib parity check" |
| } |
| this.dec.decode?(dst:in.dst, src:in.src) |
| var checksum u32 = in.src.read_u32be?() |
| // TODO: verify the checksum. |
| } |
| |
| // TODO: drop the '?' but still generate puffs_flate_adler_initialize? |
| pri struct adler32?( |
| state u32 = 1, |
| ) |
| |
| pri func adler32.update(x[] u8)(checksum u32) { |
| // The Adler-32 checksum's magic 65521 and 5552 numbers are discussed in |
| // RFC 1950. |
| |
| var s1 u32 = this.state.low_bits(n:16) |
| var s2 u32 = this.state.high_bits(n:16) |
| |
| while in.x.length() > 0 { |
| var remaining[] u8 |
| if in.x.length() > 5552 { |
| remaining = in.x[5552:] |
| in.x = in.x[:5552] |
| // TODO: this redundant if should be unnecessary. |
| if in.x.length() > 5552 { |
| return 0 // Unreachable. |
| } |
| } |
| |
| iterate (p ptr u8:in.x) { |
| // TODO: uncomment this loop body, and delete the while loop below. |
| // s1 ~+= deref p as u32 |
| // s2 ~+= s1 |
| } |
| |
| // TODO: can u64 be u32? Does it matter? |
| var i u64 |
| while i < in.x.length(), |
| inv in.x.length() <= 5552, |
| { |
| assert i < 5552 via "a < b: a < c; c <= b"(c:in.x.length()) |
| s1 ~+= in.x[i] as u32 |
| s2 ~+= s1 |
| i += 1 |
| } |
| |
| s1 %= 65521 |
| s2 %= 65521 |
| |
| in.x = remaining |
| } |
| |
| this.state = ((s2 & 0xFFFF) << 16) | (s1 & 0xFFFF) |
| return this.state |
| } |