blob: 2af48e2454374dbe07f77f769d704da1e298afc2 [file] [log] [blame]
// 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"
// TODO: move this file from std/flate to std/zlib? In doing so, we could
// rename both of "struct flate_decoder" and "struct zlib_decoder" to just
// "struct decoder", to avoid stutter in the fully qualified C name such as
// "puffs_flate__flate_decoder".
//
// Would we then need to somehow share code between test/c/std/{flate,gzip}.c?
pub struct zlib_decoder?(
flate flate_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"
}
var checksum u32
while true {
in.dst.mark()
var z status = try this.flate.decode?(dst:in.dst, src:in.src)
// TODO: expose some API to opt out of checksumming, trading off error
// detection for throughput.
checksum = this.adler.update(x:in.dst.since_mark())
if z.is_ok() {
break
}
return z
}
if checksum != in.src.read_u32be?() {
return error "checksum mismatch"
}
}
// TODO: drop the '?' but still generate puffs_flate_adler_initialize?
pri struct adler32?(
state u32 = 1,
)
// TODO: add a ! as this function is impure.
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]
}
iterate.8 (p ptr u8:in.x) {
s1 ~+= deref p as u32
s2 ~+= s1
}
s1 %= 65521
s2 %= 65521
in.x = remaining
}
this.state = ((s2 & 0xFFFF) << 16) | (s1 & 0xFFFF)
return this.state
}