-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/zstd: new internal package for zstd decompression
This package only does zstd decompression, which is starting to be used for ELF debug sections. If we need zstd compression we should use github.com/klauspost/compress/zstd. But for now that is a very large package to vendor into the standard library. For #55107 Change-Id: I60ede735357d491be653477ed419cf5f2f0d3f71 Reviewed-on: https://go-review.googlesource.com/c/go/+/473356 Reviewed-by: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Joseph Tsai <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]>
- Loading branch information
1 parent
d551401
commit 73ee0fc
Showing
12 changed files
with
2,777 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
Oops, something went wrong.