internal/pkg: decompress zstd streams
Test / Create distribution (push) Successful in 57s
Test / Sandbox (push) Successful in 3m2s
Test / ShareFS (push) Successful in 4m3s
Test / Hakurei (push) Successful in 4m16s
Test / Sandbox (race detector) (push) Successful in 5m37s
Test / Hakurei (race detector) (push) Successful in 6m49s
Test / Flake checks (push) Successful in 1m11s
Test / Create distribution (push) Successful in 57s
Test / Sandbox (push) Successful in 3m2s
Test / ShareFS (push) Successful in 4m3s
Test / Hakurei (push) Successful in 4m16s
Test / Sandbox (race detector) (push) Successful in 5m37s
Test / Hakurei (race detector) (push) Successful in 6m49s
Test / Flake checks (push) Successful in 1m11s
This uses internal/zstd until compress/zstd becomes available. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package zstd
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// block is the data for a single compressed block.
|
||||
// The data starts immediately after the 3 byte block header,
|
||||
// and is Block_Size bytes long.
|
||||
type block []byte
|
||||
|
||||
// bitReader reads a bit stream going forward.
|
||||
type bitReader struct {
|
||||
r *Reader // for error reporting
|
||||
data block // the bits to read
|
||||
off uint32 // current offset into data
|
||||
bits uint32 // bits ready to be returned
|
||||
cnt uint32 // number of valid bits in the bits field
|
||||
}
|
||||
|
||||
// makeBitReader makes a bit reader starting at off.
|
||||
func (r *Reader) makeBitReader(data block, off int) bitReader {
|
||||
return bitReader{
|
||||
r: r,
|
||||
data: data,
|
||||
off: uint32(off),
|
||||
}
|
||||
}
|
||||
|
||||
// moreBits is called to read more bits.
|
||||
// This ensures that at least 16 bits are available.
|
||||
func (br *bitReader) moreBits() error {
|
||||
for br.cnt < 16 {
|
||||
if br.off >= uint32(len(br.data)) {
|
||||
return br.r.makeEOFError(int(br.off))
|
||||
}
|
||||
c := br.data[br.off]
|
||||
br.off++
|
||||
br.bits |= uint32(c) << br.cnt
|
||||
br.cnt += 8
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// val is called to fetch a value of b bits.
|
||||
func (br *bitReader) val(b uint8) uint32 {
|
||||
r := br.bits & ((1 << b) - 1)
|
||||
br.bits >>= b
|
||||
br.cnt -= uint32(b)
|
||||
return r
|
||||
}
|
||||
|
||||
// backup steps back to the last byte we used.
|
||||
func (br *bitReader) backup() {
|
||||
for br.cnt >= 8 {
|
||||
br.off--
|
||||
br.cnt -= 8
|
||||
}
|
||||
}
|
||||
|
||||
// makeError returns an error at the current offset wrapping a string.
|
||||
func (br *bitReader) makeError(msg string) error {
|
||||
return br.r.makeError(int(br.off), msg)
|
||||
}
|
||||
|
||||
// reverseBitReader reads a bit stream in reverse.
|
||||
type reverseBitReader struct {
|
||||
r *Reader // for error reporting
|
||||
data block // the bits to read
|
||||
off uint32 // current offset into data
|
||||
start uint32 // start in data; we read backward to start
|
||||
bits uint32 // bits ready to be returned
|
||||
cnt uint32 // number of valid bits in bits field
|
||||
}
|
||||
|
||||
// makeReverseBitReader makes a reverseBitReader reading backward
|
||||
// from off to start. The bitstream starts with a 1 bit in the last
|
||||
// byte, at off.
|
||||
func (r *Reader) makeReverseBitReader(data block, off, start int) (reverseBitReader, error) {
|
||||
streamStart := data[off]
|
||||
if streamStart == 0 {
|
||||
return reverseBitReader{}, r.makeError(off, "zero byte at reverse bit stream start")
|
||||
}
|
||||
rbr := reverseBitReader{
|
||||
r: r,
|
||||
data: data,
|
||||
off: uint32(off),
|
||||
start: uint32(start),
|
||||
bits: uint32(streamStart),
|
||||
cnt: uint32(7 - bits.LeadingZeros8(streamStart)),
|
||||
}
|
||||
return rbr, nil
|
||||
}
|
||||
|
||||
// val is called to fetch a value of b bits.
|
||||
func (rbr *reverseBitReader) val(b uint8) (uint32, error) {
|
||||
if !rbr.fetch(b) {
|
||||
return 0, rbr.r.makeEOFError(int(rbr.off))
|
||||
}
|
||||
|
||||
rbr.cnt -= uint32(b)
|
||||
v := (rbr.bits >> rbr.cnt) & ((1 << b) - 1)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// fetch is called to ensure that at least b bits are available.
|
||||
// It reports false if this can't be done,
|
||||
// in which case only rbr.cnt bits are available.
|
||||
func (rbr *reverseBitReader) fetch(b uint8) bool {
|
||||
for rbr.cnt < uint32(b) {
|
||||
if rbr.off <= rbr.start {
|
||||
return false
|
||||
}
|
||||
rbr.off--
|
||||
c := rbr.data[rbr.off]
|
||||
rbr.bits <<= 8
|
||||
rbr.bits |= uint32(c)
|
||||
rbr.cnt += 8
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// makeError returns an error at the current offset wrapping a string.
|
||||
func (rbr *reverseBitReader) makeError(msg string) error {
|
||||
return rbr.r.makeError(int(rbr.off), msg)
|
||||
}
|
||||
Reference in New Issue
Block a user